11

I write a module in C# that exports some functions to be used in C. I need to allocate some memory for some structs to be passed between C <-> C#.

What I allocate in C I do with malloc, and in C# I do with Marshal.AllocHGlobal() (to allocate unmanaged memory to be passed to C).

Is there any problem if I free() the memory allocated with Marshal.AllocHGlobal, and if I release memory with Marshal.FreeHGlobal() which was allocated with malloc?

Thanks

bzamfir
  • 4,698
  • 10
  • 54
  • 89
  • Thanks. Actually what I did was to create in my lib exported functions AllocateMem, and FreeMem, which I recommended to be used by calling programs, when creating structures that are passed to lib. But I was wondering of one is not abiding to this rule and pass to my lib some structs allocated with malloc (or anything else), what should happen? – bzamfir Jan 27 '12 at 15:19
  • The issue is the structs have some pointers to char (for strings) which I have to allocate and pass to calling code. And what if the calling code attempt to free that memory with free()? That's why I created FreeMem, which I implemented with FreeHGlobal, to be used to release memory in calling prog. Otherwise it's responsability of programmer of calling code. – bzamfir Jan 27 '12 at 15:20

2 Answers2

23

The golden rule is that you must deallocate from the same heap that was used to allocate the memory.

If you allocate it with malloc(), you must deallocate it with the free() from the same C RTL. And likewise on the managed side, AllocHGlobal() should be balanced by FreeHGlobal().

Now, AllocHGlobal() is implemented by calling the Win32 function LocalAlloc. So you could free such memory with a call to LocalFree on the native side. And vice versa.

If you want to use a heap that is shared between native and managed, it is more common to use the COM heap. On the native side use CoTaskMemAlloc() and CoTaskMemFree(). On the managed side use Marshal.AllocCoTaskMem() and Marshal.FreeCoTaskMem().

However, you should avoid designing the system like this. It is much simpler to stick to a rule that all memory allocated in the managed side is deallocated there, and likewise for the native side. If you don't follow that rule you will likely soon lose track of who is responsible for what.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
3

There might or might not be a problem - this is totally implementation-dependant. Never rely on an implementation detail for your app functionality!

So I recommend not to use Marshal.AllocHGlobal(), malloc(), Marshal.FreeHGlobal() and free() crosswise.

One example, where you will run into dire trouble is if you use a library, that does some sort of fancy malloc()/free() magic - you might even not know that.

Eugen Rieck
  • 64,175
  • 10
  • 70
  • 92
  • 1
    No, it simply does not work at all! There is no might or might not about it! – David Heffernan Jan 26 '12 at 22:44
  • @DavidHeffernan Interesting! We had this in an app and it normally worked OK in Mono, things started to break with fancy libraries, so we investigated. – Eugen Rieck Jan 26 '12 at 22:46
  • 1
    That sounds like it didn't actually work. But Mono may be different beast. I'm assuming MS .net and hence the finality of my comment. – David Heffernan Jan 26 '12 at 22:50
  • 4
    @DavidHeffernan nothing to concede, please don't ge me as a "IamrightIamrightIamright" guy, I just +1ed your answer, because your "golden rule" is exactly my "recommendation". My point in my answer was more like: Even if you try it out and it works, don't do it! Follow DavidHeffernan's advice instead ... – Eugen Rieck Jan 26 '12 at 22:56