C# Interop - Releasing memory allocated in unmanaged code

穿精又带淫゛_ 提交于 2019-12-10 13:55:32

问题


I'm calling 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 a library which targets .NET 3.5. When I call this from a 3.5 assembly, it works fine; when calling it from a 4.5 assembly, however, it results in

0xC0000374: A heap has been 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 answer from Hans Passant comes with a warning:

The workaround you found is the correct one, the marshaller isn't going to try to release the memory for an IntPtr. Do note that this will only actually come to a good end if the C code returns a const char* that doesn't need to be released. You have a permanent memory leak if that's not the case.

Since the C++ method does not return const, I'm going on the assumption that the workaround for my specific function will result in a memory leak.

I cannot change the original method so I found this other question which discusses how to free memory from manged 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 how to free the memory from the pointer in managed code?

The C++ method body 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'm neither a C++ nor an Interop expert.


回答1:


Can anyone confirm that such a method will indeed suffer from a memory leak

Only you can do that, the missing const keyword is not a guarantee that the native code does not in fact return a literal. Pervasive mistake in C code btw. Write a little test program that calls the function a hundred million times. If you don't see the memory usage explode with Task Manager then you don't have a problem.

if so, suggest how to free the memory from the pointer in managed code?

You just can't, it must be the native code itself that calls free(). So that it uses the correct heap, the one that was created by the C runtime library used by that code. Underlying winapi call is HeapCreate(), you don't have the heap handle. Technically it is discoverable with GetProcessHeaps() but you just don't know which one is the "right" one. Starting with VS2012, the CRT uses GetProcessHeap() instead of HeapCreate(), now Marshal.FreeHGlobal() can work. But you know that this code doesn't, you'll have to ask the author or vendor for an update. As long as you do that, ask him for a more usable flavor of this function, it should take a char* as an argument instead.


A more constructive approach is to just take the memory leak in stride. Simply call the function once, the version number is not going to change while your program is running. So store it in a static variable. Losing ~80 bytes of address space is not a problem you can ever notice, the OS automatically cleans up when your program terminates.



来源:https://stackoverflow.com/questions/35747219/c-sharp-interop-releasing-memory-allocated-in-unmanaged-code

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!