Can someone explain me why the below C# code doesn't crash? Why does Visual Studio actually allow to compile it? My understanding is that I am getting a fixed pointer, but it is fixed only within the 'fixed' statement. When the pointer is returned from the 'Foo' function, the array 'ar' may be collected. I then force GC to actually do this, but consecutive writing to the memory (which is now deallocated) doesn't cause any error.
class Program
{
static unsafe byte* Foo()
{
byte[] ar = new byte[100];
fixed (byte* ptr = ar)
{
return ptr;
}
}
static unsafe void Main(string[] args)
{
byte* ptr = Foo();
GC.Collect();
for (int t = 0;;++t) ptr[t%100] = 0;
}
}
Eric is right, but the answer you probably want to hear is that "sometimes it's useful to retain the address outside of the fixed statement".
Maybe the memory from that pointer is already fixed by another fixed statement somewhere else, and it makes sense to return it? The compiler is not trying to second guess you and give noisy warnings.
That said, I'd hope that CodeAnalysis or other advanced tools would step in here where the compiler is letting you cut off your own foot.
Just because the memory is freed doesn't mean that writing to it would cause an error of any kind. When the garbage collector reclaims memory, it just marks it as free in it's internal memory map -- it doesn't give it back to the OS right away, so it's still valid memory for your process to use.
Of course, using a pointer outside of the fixed block for it is a very bad idea -- don't do it.
Related
I need to create a array that is aligned to a 64 byte boundary. I need to do this as I'm calling a DLL which uses AVX, which requires the data to be aligned. Essentially I need to do this in C#:
void* ptr = _aligned_malloc(64 * 1024, 64);
int8_t* memory_ptr = (int8_t*)ptr;
I'm pretty sure I can't create an array to such a boundary naturally in C#. So one option is to create an byte array that is x+64 long, and then 'create' an array that overlays it, but with an offset at the required boundary.
The problem is how do I accomplish this, and not have a memory leak? (Memory leaking is the reason I'd rather not use the DLL to create a reference to the array and pass it to C#. Unless there is a good way to do so?)
Using the helpful answers below, this is what I have, hopefully it helps others:
public class Example : IDisposable
{
private ulong memory_ptr;
public unsafe Example()
{
memory_ptr = (ulong)NativeMemory.AlignedAlloc(0x10000, 64);
}
public unsafe Span<byte> Memory => new Span<byte>((void*)memory_ptr, 0x10000);
public unsafe void Dispose()
{
NativeMemory.Free((void*)memory_ptr);
}
}
As mentioned, .NET 6 has NativeMemory.AlignedAlloc. You need to make sure to call AlignedFree otherwise you could get a leak.
void* a = default;
try
{
a = NativeMemory.AlignedAlloc(size * sizeof(long), 64);
var span = new Span<long>(a, size);
// fill span
// call DLL with span
}
finally
{
NativeMemory.AlignedFree(a);
}
A pinned GCHandle is another option for older versions of .NET. You then need to calculate the starting aligned offset with the following code, where alignment would be 64 in your case.
var ptr = (long)handle.AddrOfPinnedObject();
var offset = (int) ((ptr + alignment - 1) / alignment * alignment - ptr) / sizeof(long);
Again you need to make sure to call handle.Free in a finally.
To avoid the memory leak, first you need to pin the array. Pinning prevents the object pointed to from moving on the garbage-collected heap.
There's an example of something similar to what you're doing here.
However, that example doesn't go far enough as it only pins without controlling the initial memory allocation. To also prevent the memory leak, instead use GCHandle.Alloc with GCHandleType.Pinned. Like this.
I have come across a AccessViolationException randomly when trying to access a memory block via unsafe pointers, but only when compiling in release mode (with code optimization). The debugger is attached but will ignore any break point. For testing purposes, I just call the same function in a loop with the same arguments and eventually the exception is thrown. Without code optimization, it works correctly. The memory block is assummed to be fixed as if I try to make the pointer fixed, the compiler complains that "You cannot use the fixed statement to take the address of an already fixed expression". The memory block is allocated by a external libraries. The code is something like:
public static void TestFunct(ImageObj FloatImage)
{
try
{
unsafe
{
int memSize;
//EDIT: Missing the local copy of the image object
ImageObj FloatImageLocalCopy = FloatImage.CopyImage(); /*This local copy
will not be explicitly used after the call of GetFloatMemPointer()*/
IntPtr memHandle = FloatImageLocalCopy.GetFloatMemPointer(out memSize); /*Dll function
that returns a pointer to a float memory block*/
float * myPtr = (float *)memHandle;
//fixed(float * myPtr2 = &myPtr[0]) {} /* I tried several ways to make the
pointer fixed but compiler won't let me as it is already fixed*/
float val;
for(int i=0; i<memSize; i++)
{
val=myPtr[i]; //throws the accessViolationException sometimes!
}
}
}
catch{}
}
Then I test the function until it breaks;
//...
while(true)
{
//GC.Collect(); Thread.Sleep(5);
/*If I fire the GC before the
function, exception is not thrown (or at least it becomes very unlikely),
but I cannot afford to use it like this in
the real application*/
TestFunct(myImage);
}
//...
I have the impresion that it only breaks if the GC is collecting while loop is running but if the mem block is fixed it shouldn't be a problem, right? So, what am I doing wrong?
Thanks in advance
EDIT:
I forgot an important detail; I was not indexing the input FloatImage itseft but a local copy using .CopyImage() (just added).
PROBLEM FOUND
It turns out that when the code optimization applies, local objects can be collected even before reaching the end of its scope, if the GC thinks that they are elegible for collection as they are not used anymore. More info in: https://blogs.msdn.microsoft.com/oldnewthing/20100810-00/?p=13193 and When EXACTLY is an object eligible for garbage collection in C#?
In my case (as pointed out in the answers), the problem comes from the external libraries. The image object is fixed but they that are not providing a way of linking the lifetime of the object to the lifetime of its pointer. Thus, the GC is sometimes collecting the image while still in the unsafe loop, as the copy of the image is not used again after the call of GetFloatMemPointer().
WORKAROUND
To keep the object alive until the end of the functions it is enough to call GC.KeepAlive( FloatImageLocalCopy ); or a dummy method of the object like int memSize = FloatImageLocalCopy.GetImageSize(); after the unsafe block
Im going to assume windows?
why not do this
[DllImport("Kernel32.dll", EntryPoint = "CopyMemory", SetLastError = false)]
private static extern void CopyMemory_Win32(IntPtr dest, IntPtr src, uint size);
[DllImport("Kernel32.dll", EntryPoint = "RtlCopyMemory", SetLastError = false)]
private static extern void CopyMemory_Win64(IntPtr dest, IntPtr src, uint size);
float[] Data=new float[memsize]
var hnd = GCHandle.Alloc(obj, GCHandleType.Pinned);
IntPtr ptr = hnd.AddrOfPinnedObject();
//Get Size in bytes a float is 4 bytes long.
CopyMemory_Win64(memHandle,ptr,memsize*4);
hnd.Free();
Now you can access said data the normal way
Data[0] etc
Please have a look at the following c# code:
double* ptr;
fixed(double* vrt_ptr = &vertices[0])
{
fixed(int* tris_ptr = &tris[0])
{
ptr = compute(vrt_ptr, 5, (double*)tris_ptr, 5);
// compute() is a native C++ function
}
}
Debug.Log("Vertices Recieved: " + *ptr);
/* and so on */
I am having garbage value from *ptr. I have a suspicion that the array assigned to ptr by compute doesn't retain outside fixed block. Is it so?? Or is it due to some other problem?
This is not valid code, the garbage collector can only update the value of the vrt_ptr and tris_ptr variables. But the unmanaged code uses a copy of these pointers, the value of the copy cannot be updated by the GC. So if a garbage collection occurs while the unmanaged code is running, possible for example when other threads in the program trigger a collection, then the unmanaged code will read garbage data through the pointer copy. Very hard to diagnose, it doesn't happen very often.
You must pin the vertices and tris arrays. In your case already ably done by the pinvoke marshaller, simply by passing the arrays directly without using fixed. Fix:
double* ptr = compute(vertices, 5, tris, 5);
Adjust the pinvoke declaration accordingly, replacing double* with double[].
You'll now also have to the deal with the likely reason you wrote this code in the first place. There is no scenario where casting an int[] to double[] is ever valid, the likely reason you got a garbage result early before that GC disaster could strike. If you can't update the declaration of tris for some reason then you must create a double[] before the call.
Is this going to break? It compiles fine but based on readings, I'm unsure if its guaranteed that _ptRef will always point to the struct referenced in the constructor.
I guess by 'break' I mean...will the GC move the struct pointed to by the pointer (_ptRef)?
public unsafe class CPointType0
{
private PointType0* _ptRef = null;
public CPointType0(ref PointType0 spt)
{
fixed (PointType0 * pt = &spt)
{
_ptRef = pt;
}
}
...a bunch of property accessors to fields of _ptRef (accessed as return _ptRef->Thing) }
The scenario is
-PointType0 is a struct.
-millions of PointType0's in memory in a data structure. These used to be reference types but there gets to be way too much memory overhead.
-A List is returned only when a search operation finds a relevant PointType0, and this List is passed around and operated on a lot.
It's not safe.
After the code leaves the fixed block, the garbage collector is free to move things around again. What are you trying to accomplish here? Do you maybe want to use the index of an item in the list, instead of a pointer?
In C#, it's possible to declare a struct (or class) that has a pointer type member, like this:
unsafe struct Node
{
public Node* NextNode;
}
Is it ever safe (err.. ignore for a moment that ironic little unsafe flag..) to use this construction? I mean for longterm storage on the heap. From what I understand, the GC is free to move things around, and while it updates the references to something that's been moved, does it update pointers too? I'm guessing no, which would make this construction very unsafe, right?
I'm sure there are way superior alternatives to doing this, but call it morbid curiosity.
EDIT: There appears to be some confusion. I know that this isn't a great construction, I purely want to know if this is ever a safe construction, ie: is the pointer guaranteed to keep pointing to whatever you originally pointed it to?
The original C-code was used to traverse a tree (depth first) without recursion, where the tree is stored in an array. The array is then traversed by incrementing a pointer, unless a certain condition is met, then the pointer is set to the NextNode, where traversal continues. Of course, the same can in C# be accomplished by:
struct Node
{
public int NextNode;
... // other fields
}
Where the int is the index in the array of the next node. But for performance reasons, I'd end up fiddling with pointers and fixed arrays to avoid bounds checks anyway, and the original C-code seemed more natural.
Is it ever safe to use this construction? I mean for long term storage on the heap.
Yes. Doing so is usually foolish, painful and unnecessary, but it is possible.
From what I understand, the GC is free to move things around, and while it updates the references to something that's been moved, does it update pointers too?
No. That's why we make you mark it as unsafe.
I'm guessing no, which would make this construction very unsafe, right?
Correct.
I'm sure there are way superior alternatives to doing this, but call it morbid curiosity.
There certainly are.
is the pointer guaranteed to keep pointing to whatever you originally pointed it to?
Not unless you ensure that happens. There are two ways to do that.
Way one: Tell the garbage collector to not move the memory. There are two ways to do that:
Fix a variable in place with the "fixed" statement.
Use interop services to create a gc handle to the structures you wish to keep alive and in one place.
Doing either of these things will with high likelihood wreck the performance of the garbage collector.
Way two: Don't take references to memory that the garbage collector can possibly move. There are two ways to do that:
Only take addresses of local variables, value parameters, or stack-allocated blocks. Of course, in doing so you are then required to ensure that the pointers do not survive longer than the relevant stack frame, otherwise, you're referencing garbage.
Allocate a block out of the unmanaged heap and then use pointers inside that block. In essence, implement your own memory manager. You are required to correctly implement your new custom memory manager. Be careful.
Some obvious integrity checks have been excluded. The obvious problem with this is you have to allocate more than you will need because you cannot reallocate the buffer as the keyword fixed implies.
public unsafe class NodeList
{
fixed Node _Nodes[1024];
Node* _Current;
public NodeList(params String[] data)
{
for (int i = 0; i < data.Length; i++)
{
_Nodes[i].Data = data[i];
_Nodes[i].Next = (i < data.Length ? &_Nodes[i + 1] : null);
}
_Current = &_Nodes[0];
}
public Node* Current()
{
return _Current++;
}
}
public unsafe struct Node
{
public String Data;
public Node* Next;
}
Why not:
struct Node
{
public Node NextNode;
}
or at least:
struct Node
{
public IntPtr NextNode;
}
You could use the fixed statement to prevent the GC to move pointers around.
Yes, the garbage collector can move the objects around and, no, it will not update your pointers. You need to fix the objects you point to. More information can be found on this memory management explanation.
You can fix objects like this:
unsafe {
fixed (byte* pPtr = object) {
// This will fix object in the memory
}
}
}
The advantages of pointers are usually performance and interaction with other unsafe code. There will be no out-of-bounds checks etc, speeding up your code. But just as if you were programming in e.g. C you have to be very careful of what you are doing.
A dangerous idea, but it may work:
When your array of structs exceeds a certain size (85000 bytes) it will be allocated on the Large Object Heap where blocks are scanned and collected but not moved...
The linked article points out the danger that a newer CLR version might move stuff on the LOH...