Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deleting C# Unsafe Pointers

I know using the /unsafe flag in C#, you can use pointers. In C/C++ to delete a pointer you would use free(pointer); and delete pointer; respectively. However, how would you achieve the same effect with the C# pointers?

like image 764
inixsoftware Avatar asked Aug 11 '13 14:08

inixsoftware


People also ask

What is delete in C?

delete keyword in C++ Delete is an operator that is used to destroy array and non-array(pointer) objects which are created by new expression. Delete can be used by either using Delete operator or Delete [ ] operator. New operator is used for dynamic memory allocation which puts variables on heap memory.

Does C have Delete function?

There's no new / delete expression in C. The closest equivalent are the malloc and free functions, if you ignore the constructors/destructors and type safety.

Can I delete C files?

To delete a file using C language, use remove() function of stdio. h. remove() function takes file name (or path if not located in the same location) as argument and deletes the file. remove() returns 0 if the file is deleted successfully, else it returns a non-zero value.

Is delete a key word in C?

The delete keyword replaces the free function in C and will release storage reserved with new. int *ptr1; // Declare a pointer to int.


1 Answers

It depends. You use free and delete to free memory allocated with malloc and new.

but

in general if you do a PInvoke call, then the pointer should be a IntPtr.

if you use fixed (or GCHandle) to obtain a pointer for a managed object, then the memory was allocated from the GC memory

  • For the memory of GC, when you un-pin that memory (exit the fixed block, or release the GCHandle), the GC will return handling it
  • For memory allocated through .NET Marshal methods you use the complementary Free method
  • For memory received from native methods, you have to use the "correct" native method to free it.

Example of pinning memory received by the .NET:

int[] arr = new int[5];

fixed (int* p = arr)
{
    // here arr is fixed in place and it won't be freed/moved by gc
}

// here arr is un-fixed and the GC will manage it

or, nearly equivalent (but a little less safe, because the unpinning is done manually)

GCHandle handle = GCHandle.Alloc(arr, GCHandleType.Pinned);

int* p2 = (int*)handle.AddrOfPinnedObject();

// here arr is fixed in place and it won't be freed/moved by gc

handle.Free();
// here arr is un-fixed and the GC will manage it

Example of allocating some memory from the "native" pool (through the allocator normally used by COM objects) by using Marshal.AllocCoTaskMem (note that Marshal.AllocCoTaskMem calls the CoTaskMemAlloc of Windows API, so you can use both Marshal.FreeCoTaskMem and the Windows API CoTaskMemFree to free it):

// allocating space for 1000 chars
char* p3 = (char*)Marshal.AllocCoTaskMem(1000 * sizeof(char));

// here you can use p3

// and here you free it
Marshal.FreeCoTaskMem((IntPtr)p3);

or with another allocator supported by Marshal (this is the one normally used by Windows API):

// allocating space for 1000 chars
char* p4 = (char*)Marshal.AllocHGlobal(1000 * sizeof(char));

// here you can use p4

// and here you free it
Marshal.FreeHGlobal((IntPtr)p4);

Let's say you have some Native code that gives you access to some memory where it saves some data:

static extern IntPtr GetSomeMemoryFromSomeWinApi();

static extern void FreeSomeMemoryFromSomeWinApi(IntPtr ptr);

You use like this:

IntPtr p5 = GetSomeMemoryFromSomeWinApi();

// here you have some memory received from some native API

// and here you free it
FreeSomeMemoryFromSomeWinApi(p5);

In this case it's your library that has to give you a Free method, because you don't know how the memory was allocated, but sometimes your library's documentation tells you that the memory is allocated through a specific allocator, so you use that type of deallocator to free it, like

Marshal.FreeCoTaskMem(p5);

if the API was some COM object.

The Marshal class even has the allocator for BSTR (Unicode strings used by COM objects. They have their length pre-pendend)

string str = "Hello";
char *bstr = (char*)Marshal.StringToBSTR(str);

Marshal.FreeBSTR((IntPtr)bstr);

They have special handling because their "real" start address is like (bstr - 2) (they had an Int32 prepended with their length)

The point is that there are as many allocators as the grain of sand of the desert and the stars of the sky. Every one of them (with the exception of the standard one of .NET, the one used by new) has a corresponding deallocator. They go like husband and wife. They don't mix with others.

As a final note, if you write mixed .NET/native C or C++ code, you'll have to expose some C/C++ methods that call their free/delete, because their free/delete are part of their C/C++ libraries, not of the OS.

like image 139
xanatos Avatar answered Sep 21 '22 15:09

xanatos