In C# book is written that I'm unable to access unallocated memory. They said that is possible in unsafe context. My question is how this can be done?
I tried something like this:
static void Main(string[] args)
{
unsafe
{
int c;
Console.WriteLine(c);
}
}
With allow unsafe option in project properties. And this code is unable to compile.
The unsafe keyword does not completely alter the language or compilation model, you still need to initialize any variables before using them. If you want to access "unallocated memory", you need to get a pointer to that memory. Here is an example:
unsafe void AccessMemory()
{
const int address = 10000;
byte[] array = new byte[0];
fixed (byte* zero = array)
{
byte* p = zero + address;
}
}
Here we get a pointer to the empty array, which gives the zero pointer. Then we offset that pointer by some amount (address), which results in a pointer to that memory address.
Related
interoping nim dll from c# i could call and execute the code below
if i will add another function (proc) that Calls GetPacks() and try to echo on each element's buffer i could see the output in the C# console correctly
but i could not transfer the data as it is, i tried everything but i could not accomplish the task
proc GetPacksPtrNim(parSze: int, PackArrINOUT: var DataPackArr){.stdcall,exportc,dynlib.} =
PackArrINOUT.newSeq(parSze)
var dummyStr = "abcdefghij"
for i, curDataPack in PackArrINOUT.mpairs:
dummyStr[9] = char(i + int8'0')
curDataPack = DataPack(buffer:dummyStr, intVal: uint32 i)
type
DataPackArr = seq[DataPack]
DataPack = object
buffer: string
intVal: uint32
when i do same in c/c++ the type i am using is either an IntPtr or char*
that is happy to contain returned buffer member
EXPORT_API void __cdecl c_returnDataPack(unsigned int size, dataPack** DpArr)
{
unsigned int dumln, Index;dataPack* CurDp = {NULL};
char dummy[STRMAX];
*DpArr = (dataPack*)malloc( size * sizeof( dataPack ));
CurDp = *DpArr;
strncpy(dummy, "abcdefgHij", STRMAX);
dumln = sizeof(dummy);
for ( Index = 0; Index < size; Index++,CurDp++)
{
CurDp->IVal = Index;
dummy[dumln-1] = '0' + Index % (126 - '0');
CurDp->Sval = (char*) calloc (dumln,sizeof(dummy));
strcpy(CurDp->Sval, dummy);
}
}
c# signature for c code above
[DllImport(#"cdllI.dll", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
private static extern uint c_returnDataPack(uint x, DataPackg.TestC** tcdparr);
C# Struct
public unsafe static class DataPackg
{
[StructLayout(LayoutKind.Sequential)]
public struct TestC
{
public uint Id;
public IntPtr StrVal;
}
}
finally calling the function like so:
public static unsafe List<DataPackg.TestC> PopulateLstPackC(int ArrL)
{
DataPackg.TestC* PackUArrOut;
List<DataPackg.TestC> RtLstPackU = new List<DataPackg.TestC>(ArrL);
c_returnDataPack((uint)ArrL, &PackUArrOut);
DataPackg.TestC* CurrentPack = PackUArrOut;
for (int i = 0; i < ArrL; i++, CurrentPack++)
{
RtLstPackU.Add(new DataPackg.TestC() { StrVal = CurrentPack->StrVal, Id = CurrentPack->Id });
}
//Console.WriteLine("Res={0}", Marshal.PtrToStringAnsi((IntPtr)RtLstPackU[1].StrVal));//new string(RtLstPackU[0].StrVal));
return RtLstPackU;
}
how could i produce similar c code as above from Nim ?
it doesn't have to be same code, but same effect, that in c# i would be able to read the content of the string. for now, the int is readable but the string is not
Edit:
this is what i tried to make things simple
struct array of int members
Update:
it seem that the problem is to do with my settings of nim in my windows OS.
i will be updating as soon as i discover what exactly is wrong.
The string type in Nim is not equivalent to the C's const char* type. Strings in Nim are represented as pointers, pointing into a heap-allocated chunk of memory, which has the following layout:
NI length; # the length of the stored string
NI capacity; # how much room do we have for growth
NIM_CHAR data[capacity]; # the actual string, zero-terminated
Please beware that these types are architecture specific and they are really an implementation detail of the compiler that can be changed in the future. NI is the architecture-default interger type and NIM_CHAR is usually equivalent to a 8-bit char, since Nim is leaning towards the use of UTF8.
With this in mind, you have several options:
1) You can teach C# about this layout and access the string buffers at their correct location (the above caveats apply). An example implementation of this approach can be found here:
https://gist.github.com/zah/fe8f5956684abee6bec9
2) You can use a different type for the buffer field in your Nim code. Possible candidates are ptr char or the fixed size array[char]. The first one will require you to give up the automatic garbage collection and maintain a little bit of code for manual memory management. The second one will give up a little bit of space efficiency and it will put hard-limits on the size of these buffers.
EDIT:
Using cstring may also look tempting, but it's ultimately dangerous. When you assign a regular string to a cstring, the result will be a normal char * value, pointing to the data buffer of the Nim string described above. Since the Nim garbage collector handles properly interior pointers to allocated values, this will be safe as long as the cstring value is placed in a traced location like the stack. But when you place it inside an object, the cstring won't be traced and nothing prevents the GC from releasing the memory, which may create a dangling pointer in your C# code.
Try to change your struct to:
public unsafe static class DataPackg
{
[StructLayout(LayoutKind.Sequential)]
public struct TestC
{
public uint Id;
[MarshalAs(UnmanagedType.LPStr)]
public String StrVal;
}
}
I do have the follwing struct in a C# wrapper for some unmanaged code. I try to hand over some data using pointers, which is fine for the ushort* and byte* part, but does not work for the fixed int.
[StructLayout(LayoutKind.Sequential)]
unsafe public struct IMAGE
{
public fixed int nSize[2];
public ushort* pDepthIm;
public byte* pColorIm;
}
To fill this struct with some information, I use:
unsafe public void LoadImage(ushort[] depthImage, byte[] rgbImage, int[] size)
{
unsafe
{
fixed (int* pSize = size)
fixed (ushort* pDepth = depthImage)
fixed (byte* pRGB = rgbImage)
{
_im.nSize = pSize;
_im.pColorIm = pRGB;
_im.pDepthIm = pDepth;
...
}
}
}
At _im.nSize = pSize; the compiler shows an error, stating:
You cannot use fixed size buffers contained in unfixed expressions.
Try using the fixed statement.
I already noticed that the int is initialized in a different way (not with the Pointer-*, but as fixed int), but I can't figure out how to hand over the value. When hovering over the variable, it is shown as int*...
Update: I came across the MSDN error reference for the mentioned message. I'm now sure it has to do with the fixed statement in the IMAGE struct, but I still have no idea how to fix it.
You can't assign a pointer to an array. You have to use memcpy.
memcpy(_im.nSize, size, sizeof(_im.nSize));
As a matter of fact you can't assign anything to an array. You can modify array's value, but not reassign it.
I would also check for the array length, pass it as a parameter or check it's .length if the languge allows it.
If found a way to access the fixed int[2] like this:
public unsafe void LoadImage(ushort[] depthImage, byte[] rgbImage, int[] size)
{
unsafe
{
fixed (int* pSize = _im.nSize)
fixed (ushort* pDepth = depthImage)
fixed (byte* pRGB = rgbImage)
fixed (S_IMAGE* pim = &_im)
{
pSize[0] = size[0];
pSize[1] = size[1];
_im.pColorIm = pRGB;
_im.pDepthIm = pDepth;
}
}
}
Im not sure if this is a good way or if this is how it is meant to be, but at least it works as expected...
Iirc from C, you can have a statement along these lines:
char* str = "1234";
int nonStr = *((int*)str);
(I intentionally made the string 4 characters so in the average scenario it will have the same number of bytes as the integer.) This will dereference the memory where str is stored and give you the value if it was an integer (522207554 if I did the conversion right).
Is there any way to do the same thing in C#? I know this is a low level memory operation which is generally blissfully hidden from the C# programmer, I am only doing this for a teaching exercise.
You can do this using unsafe context and fixedstatement:
static unsafe void Main(string[] args)
{
string str = "1234";
fixed(char* strPtr = str)
{
int* nonStr = (int*)strPtr;
Console.WriteLine(*nonStr);
}
}
prints
3276849
You're looking for the unsafe functionality of C#.
Here's one reference. A general search for "C# unsafe pointer dereference" turns up many results.
Would a union simulation be sufficient for this?
http://msdn.microsoft.com/en-us/library/acxa5b99.aspx
I need some C# code to convert a double to a byte*. I know I have to use fixed (and unsafe?), but not exactly sure how...
As long as the double variable has stack scope (local variable or method argument), you can simply use a pointer cast. This works because stack scope variables are not subject to moving by the garbage collector and thus don't have to be pinned. Avoids having to convert the double to byte[] first. The same restrictions apply as with the fixed keyword, the pointer is only valid inside the method body:
unsafe void Foo(double d) {
byte* ptr = (byte*)&d;
// Use ptr
//...
}
Exact same thing that the BitConverter class does.
You can do:
unsafe
{
fixed (byte* b = BitConverter.GetBytes(1.2d))
{
// Do stuff...
}
}
or :
public unsafe void YourMethod(double d)
{
fixed (byte* b = BitConverter.GetBytes(d))
{
// Do stuff...
}
}
Use BitConverter.GetBytes method: http://msdn.microsoft.com/en-us/library/a5be4sc9.aspx
double d = 2.0;
byte[] array = BitConverter.GetBytes(d);
Edit: if you need a C-style byte* use:
double d = 2;
byte[] array = BitConverter.GetBytes(d);
IntPtr ptr = Marshal.AllocHGlobal(sizeof(byte) * array.Length);
Marshal.Copy(array, 0, ptr, array.Length);
unsafe
{
byte* pointer = (byte*)ptr;
}
You can start by using BitConverter.GetBytes()
As most people here have stated, you can use fixed, or BitConverter to do this. But mostly, don't. If you need data marshalled, .NET will do this for you. In most cases you do not want to pass references to managed memory to unmanaged functions (as you will have no control over the state of the data, or the references)
'Fixed' will make sure that within the scope, the data will not be moved or released by the garbage collector, and you will get your pointer. However, outside of the fixed block, unmanaged code might still have that pointer, even though the pointer may have been invalidated by the garbage collector, which will promptly make your application fail without any obvious cause.
In .NET, you seldom get any favorable performance increase by using unsafe code, and passing out references to managed data to unmanaged code is not always favorable.
But there are several answers:
byte value = 255;
unsafe
{
byte* ptr = &value; // Assign the address of value to ptr
SomeUnsafeCode(ptr);
}
You don't need to use fixed on stack allocated variables, as they are not garbage collected.
For garbage collected variables, you will need fixed:
byte[] array = SomeGenerator();
unsafe
{
fixed(byte* ptr = array)
{
SomeUnsafeCode(ptr);
}
}
This will pin the array to memory, so that the grabage collector will not touch the array while it is fixed.
Sometimes you would want to pin data over several blocks of code. In this case you would want to use System.Runtime.InteropServices.GCHandle.
in C#, is there a way to
Get the memory address stored in a
reference type variable?
Get the memory address of a
variable?
EDIT:
int i;
int* pi = &i;
How do you print out the hex value of pi?
For #2, the & operator will work in the same fashion as in C. If the variable is not on the stack, you may need to use a fixed statement to pin it down while you work so the garbage collector does not move it, though.
For #1, reference types are trickier: you'll need to use a GCHandle, and the reference type has to be blittable, i.e. have a defined memory layout and be bitwise copyable.
In order to access the address as a number, you can cast from pointer type to IntPtr (an integer type defined to be the same size as a pointer), and from there to uint or ulong (depending on the pointer size of the underlying machine).
using System;
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
class Blittable
{
int x;
}
class Program
{
public static unsafe void Main()
{
int i;
object o = new Blittable();
int* ptr = &i;
IntPtr addr = (IntPtr)ptr;
Console.WriteLine(addr.ToString("x"));
GCHandle h = GCHandle.Alloc(o, GCHandleType.Pinned);
addr = h.AddrOfPinnedObject();
Console.WriteLine(addr.ToString("x"));
h.Free();
}
}
Number 1 is not possible at all, you can't have a pointer to a managed object. However, you can use an IntPtr structure to get information about the address of the pointer in the reference:
GCHandle handle = GCHandle.Alloc(str, GCHandleType.Pinned);
IntPtr pointer = GCHandle.ToIntPtr(handle);
string pointerDisplay = pointer.ToString();
handle.Free();
For number 2 you use the & operator:
int* p = &myIntVariable;
Pointers of course have to be done in a unsafe block, and you have to allow unsafe code in the project settings. If the variable is a local variable in a method, it's allocated on the stack so it's already fixed, but if the variable is a member of an object, you have to pin that object in memory using the fixed keyword so that it's not moved by the garbage collector.
To answer your question most correctly:
#1 is possible but a bit tricky, and should be only done for debugging reasons:
object o = new object();
TypedReference tr = __makeref(o);
IntPtr ptr = **(IntPtr**)(&tr);
This works for any object and actually returns the internal pointer to the object in memory. Remember the address can change at any moment because of the GC, which likes to move objects across the memory.
#2 Pointers aren't objects and thus don't inherit ToString from them. You have to cast the pointer to IntPtr like so:
Console.WriteLine((IntPtr)pi);