views:

264

answers:

2

My program uses a third party dynamic link library that has huge memory leaks inside. Both my program and the library are Visual C++ native code. Both link to the Visual C++ runtime dynamically.

I'd like to force the library into another heap so that all allocations that are done through the Visual C++ runtime while the library code is running are done on that heap. I can call HeapCreate() and later HeapDestroy(). If I somehow ensure that all allocations are done in the new heap I don't care of the leaks anymore - they all go when I destroy the second heap.

Is it possible to force the Visual C++ runtime to make all allocations on a specified heap?

+3  A: 

Sorry my last answer got posted half-baked, i pressed tab and enter without remembering this was a text box and not an editor...

Anyway heres it in full :

You can use the detours library to hook the allocation and deallocation functions, replace them with your own :

Vaguely something like this :

//declare a global 
HANDLE g_currentHeap;

LPVOID WINAPI HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes) 
{ 
    return OriginalHeapAlloc(g_currentHeap, dwFlags, dwBytes);
}


BOOL WINAPI HeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem)
{
    return OriginalHeapFree(g_currentHeap, dwFlags, lpMem);
}

in the application load

HANDLE g_Heaps[2];

int main()
{
    // Two heaps
    g_Heaps[0] = HeapCreate(...);
    g_Heaps[1] = HeapCreate(...);


    // Do whatevers needed to hook HeapAlloc and HeapFree and any other heap functions 
    // and redirect them to the versions above
    // Save the old function pointers so we can call them
}

Then everytime you call an API from the 3rd party DLL you can do this

void someFn()
{
    g_currentHeap = g_Heaps[1];
    Some3rdPartyAPI();
    g_currentHeap = g_Heaps[0];

    SomeOtherFunction();

}

This should solve your problem

@peterchen : The C++ runtime calls HeapAlloc for new and malloc() so this approach will work. In fact I believe almost any languages runtime will use the win32 Heap functions, unless there was a special reason not to.

rep_movsd
At least in VC6, HeapAlloc was always called in Debug Builds, in Release Builds, a custom memory manager kicked in for msot allocations. *I don't know* if this has changed in VS2005/2008 - needs to be verified.
peterchen
The CRT source for Visual Studio 8 does seem to call HeapAlloc()I put a breakpoint on HeapAlloc() in release mode on a test program....Seems that it is being called on every malloc() and new.
rep_movsd
Detours is very useful, but care is needed especially if there are multiple threads about. I've run into some very tricky issues around debugging with it. Best bet, if you choose to use it, is to initialize and setup all your detour-ed functions before loading any other DLLs or starting any threads other than the main one. Else you can run into tricky situations where another thread may already be inside the function your are trying to detour.
cpalmer
A: 

Redirecting only the DLL's allocations is tricky at best if both binaries link to it the same way.

The most robust way I can think of is moving the DLL into a separate process. That's fairly easy for a COM DLL that uses only IDispatch interfaces or provides a proxy/stub DLL. You would need to write a custom wrapper otherwise - depending on the DLL's API that's a lot of work or might be a performance problem.

If require to remain in-process, you could hook CRT allocations, and redirect allocations made by the library to another allocator (such as a Win32 heap).

The mine/theirs decision would safest be made by wrapping all calls to the library that sets a global flag. Alternatively, you could inspect thecall stack - but that won't work in all scenarios. With both solutions, watch out for callback implemented in your code but called by the library.

[edit] _CRTSetAllocHook does work in debug buils only, though.

peterchen
Will hooking allocations work for non-debug version of the CRT?
sharptooth
You are right, _CrtSetDebugHook works only in debug builds, too. You can check out detours as suggested by rep_movsd if they work in release builds for all allocations, too. Otherwise... a quick google doesn't turn up anything conclusive. Maybe wait for other replies, or open it as a new question.
peterchen