This certainly did not used to work. But things have been changing. The C runtime library was changed in VS2012 and it no longer creates its own heap anymore. For VS2015, this code in C:\Program Files (x86)\Windows Kits\10\Source\10.0.10240.0\ucrt\heap\heap_handle.cpp is relevant:
// 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;
}
Note the call to GetProcessHeap(), it returns the same heap that Marshal.AllocHGlobal() allocates from. So yes, you are not going to get an exception from the debug heap nor a leak when you de-allocate with Marshal.FreeHGlobal().
Much the same for CoTaskMemAlloc(). Single-stepping into the function, I see:
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)]
Note the usage of the g_hHeap
variable. I see it have the same value as GetProcessHeap() returns. So again, releasing with any of the deallocation functions is going to work just fine.
Do note that this I got this from Windows 10, an older version of Windows is not going to behave the same way. And note CRetailMalloc_Alloc, a not so pleasant randomizer with an unpredictable usage.
While this was certainly meant to be helpful, a lot less ways in which programs can fail, it isn't actually useful when you test your app. Nasty, really, it invokes the "only works on my machine" failure mode. Bah.