views:

392

answers:

3

I have an exe using a dll which is using another dll. This situation has arisen:

In dll1:

class abc
{
    static bool FindSubFolders(const std::string & sFolderToCheck, 
                               std::vector< std::string > & vecSubFoldersFound);
}

In dll2:

void aFunction()
{
    std::vector<std::string> folders;
    std::string sLocation;
    ...
    abc::FindSubFolders(sLocation, folders)
}

In release mode, everything works fine. But in debug mode, I come up with an assertion failure in the destructor of one of the std::strings in the folders vector (when folders goes out of scope at the end of aFunction):

dbgheap.c : line 1274

/*
 * If this ASSERT fails, a bad pointer has been passed in. It may be
 * totally bogus, or it may have been allocated from another heap.
 * The pointer MUST come from the 'local' heap.
 */
_ASSERTE(_CrtIsValidHeapPointer(pUserData));

I assume this is because the memory has been allocated on dll1's heap, but is being freed in dll2.

The comment in dbgheap.c seems pretty insistent that this is a problem.

Why is this such a problem, when it seems to work fine if I just ignore it? Is there a non-assertion-failing way of doing this?

+4  A: 

Most likely, the release build has the same problem, but release builds don't assert. They just ignore the problem. You might never see an issue. Or you might see data corruption. Or you might see a crash. Maybe only your users will experience bugs that you are simply not able to reproduce.

Don't ignore CRT assertions.

You should always use the appropriate deallocator (the one that matches the allocator used to begin with). If you are using static CRT libraries in your dlls, the dlls are using different heaps. You can not deallocate memory across heaps. Allocate and deallocate a block of memory using the same heap.

If you are using shared CRT libraries in your dlls, then they should be using the same heap and you can allocate in one dll and deallocate in another.

sean e
cf. Raymond Chen: http://blogs.msdn.com/oldnewthing/archive/2006/09/15/755966.aspx
James McNellis
+1 - Thank you!
Smashery
+3  A: 

As sean has already said, the release build simply ignores that delete statement, so the best you can hope for is a memory leak.

If you have control over how both dlls are compiled, make sure to use the Multi-threaded Debug DLL (/MDd) or Multi-threaded DLL (/MD) settings for runtime library. That way, both dlls will use the same runtime system and share the same heap.

The downside is that you need to install the runtime system together with your application (Microsoft offers an installer for that). It will work fine on your development machine since Visual Studio installs that runtime system too, but on a freshly installed machine it will report missing dlls.

Hans
My Project Properties were wrong - I didn't have Debug DLL (/MDd) set - it now works fine. Thanks!
Smashery
+1  A: 

This is only a problem if the application or one (or more) of the dll is linked against the static version of the standard library. This was solved about a decade ago by MS releasing the shared library version of the standard library. This is because each version of the standard library will build it own internal heap and thus with multiple heaps you must release the memory to the correct heap. By using the shared version of the standard library they all use the same heap.

It is standard practice nowadays for the application and all dll should be built to use the dynamic version of the standard library.

The only caveat to the above is if you create your own heap and allocate memory from this heap. But this is a very specialized procedure only done in rare situations (and if you understand enough to use it then you will not be in the situation of asking this question).

Martin York