C # Interop - freeing memory allocated in unmanaged code

I call the following VC ++ method

__declspec(dllexport) unsigned char* Get_Version_String() 

from C # as follows:

 internal static class NativeMethods { [DllImport("my.dll"), CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true, CallingConvention = CallingConvention.Cdecl)] internal static extern string Get_Version_String(); } 

The above code is in the library which is for .NET 3.5. When I call this from assembly 3.5, it works fine; however, calling it from assembly 4.5, this leads to

0xC0000374: heap is corrupted

After reading this question , I changed my method calls as follows:

 [DllImport("my.dll", EntryPoint = "Get_Version_String", CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true, CallingConvention = CallingConvention.Cdecl)] private static extern IntPtr Get_Version_String_PInvoke(); internal static string Get_Version_String() { IntPtr ptr = Get_Version_String_PInvoke(); string versionString = Marshal.PtrToStringAnsi(ptr); return versionString; } 

This works as expected, but the response from Hans Passant comes with a warning:

The workaround you found is correct; the marshaller is not going to release memory for IntPtr . Note that this only actually comes to an end if the C code returns a const char* that does not need to be released. If this is not the case, you have a persistent memory leak.

Since the C ++ method does not return const , I proceed from the assumption that a workaround for my specific function will lead to a memory leak.

I cannot change the original method, so I found this other question that discusses how to free memory from coordinated code. However, calling either Marshal.FreeHGlobal(ptr) or Marshal.FreeCoTaskMem(ptr) also throw 0xC0000374: A heap has been corrupted.

Can anyone
a) confirm that such a method will indeed suffer from a memory leak and
b) if so, suggest freeing up memory from a pointer in managed code?

The body of the C ++ method is simplified as follows:

 unsigned char versionString[50]; __declspec(dllexport) unsigned char* Get_Version_String() { strcpy((char *) versionString, "Key1:[xx],Key2:[xx],Key3:[xx],Key4:[xx]"); // string manipulation return versionString; } 

Thanks in advance, and sorry if this is trivial; I am neither a C ++ nor an Interop expert.

+5
source share
1 answer

Can anyone confirm that such a method really suffers from a memory leak

Only you can do this, the missing const keyword does not guarantee that native code does not actually return a literal. A pervasive bug in C code. Write a small test program that calls a function a hundred million times. If you do not see that the memory usage exploded using the Task Manager, you have no problem.

if so, suggest freeing up memory from a pointer in managed code?

You just can't, it must be your own code that calls free() . So it uses the correct heap, one that was created by the C runtime library used by this code. The main winapi call is HeapCreate (), you do not have a heap descriptor. Technically, this can be detected using GetProcessHeaps (), but you just don’t know which one is the β€œcorrect” one. Starting from VS2012, CRT uses GetProcessHeap () instead of HeapCreate (), now Marshal.FreeHGlobal () can work. But you know that this code is not there, you will have to ask the author or provider to update. While you are doing this, ask him to use this parameter, which is more convenient for use, char * should be used instead.


A more constructive approach is to ease the memory leak in a step. Just call the function once, the version number will not change while your program is running. Therefore, save it in a static variable. Losing ~ 80 bytes of address space is not a problem that you have ever noticed, the OS is automatically cleared when your program terminates.

+6
source

Source: https://habr.com/ru/post/1244291/


All Articles