CoTaskMemAlloc v malloc v AllocHGlobal

Mic*_*lGG 2 c c# pinvoke winapi

我在Windows上看过,malloc与CoTaskMemAlloc不同,后者与AllocHGlobal不同.对于C#使用者来说,这可能意味着如果我有一个返回malloc指针的C函数,我需要在其上调用free.如果IP/Invoke并指定字符串返回类型,则CLR应该调用CoTaskMemFree并且应该在malloc指针上失败.

但是,我无法在实践中看到这一点.我创建了一个DLL,它只返回一个malloc'd char*和P/Invoked它作为一个字符串.没有内存泄漏.实际上,无论我尝试什么,我都无法让事情失败.我调用malloc,GlobalHAlloc,CoTaskMemAlloc,然后使用任何免费的实现,只是工作.没有内存泄漏.重新使用相同的内存空间.

我怎么能强迫它失败?或者这是那些应该是"实现定义"的东西,但实际上只是单向工作?

这是在VS2015 Update 2,Windows 8.1上.

Han*_*ant 6

这当然不习惯工作.但事情一直在变化.在VS2012中更改了 C运行时库,它不再创建自己的堆.对于VS2015,此代码在C:\ Program Files(x86)\ Windows Kits\10\Source\10.0.10240.0\ucrt\heap\heap_handle.cpp中是相关的:

// Initializes the heap.  This function must be called during CRT startup, and
// must be called before any user code that might use the heap is executed.
extern "C" bool __cdecl __acrt_initialize_heap()
{
    __acrt_heap = GetProcessHeap();
    if (__acrt_heap == nullptr)
        return false;

    return true;
}
Run Code Online (Sandbox Code Playgroud)

注意对GetProcessHeap()的调用,它返回Marshal.AllocHGlobal()分配的相同堆.所以是的,当您使用Marshal.FreeHGlobal()取消分配时,您不会从调试堆中获得异常,也不会泄漏.

CoTaskMemAlloc()大致相同.单步进入功能,我看到:

7638D1E1  mov         esi,dword ptr [g_CMalloc (76485EE0h)]  
7638D1E7  push        dword ptr [ebp+8]  
7638D1EA  mov         esi,dword ptr [esi+0Ch]  
7638D1ED  cmp         esi,offset CRetailMalloc_Alloc (763732C0h)  
7638D1F3  jne         CoTaskMemAlloc+44h (7638D214h)  
7638D1F5  push        0  
7638D1F7  push        dword ptr [g_hHeap (76485E68h)]  
7638D1FD  call        dword ptr [__imp__HeapAlloc@12 (76488228h)] 
Run Code Online (Sandbox Code Playgroud)

注意g_hHeap变量的用法.我看到它与GetProcessHeap()返回的值相同.因此,使用任何释放函数释放都可以正常工作.

请注意,我从Windows 10获得此功能,Windows的旧版本不会以相同的方式运行.并注意CRetailMalloc_Alloc,一个不太令人愉快的随机函数,具有不可预测的用法.

虽然这当然是有帮助的,但程序失败的方式要少得多,但在测试应用程序时实际上并没有用.讨厌,真的,它调用"只能在我的机器上工作"故障模式.呸.