Freeing memory allocated in a different DLL
I have an EXE file using a DLL file which is using another DLL file. This situation has arisen:
In DLL file 1:
class abc
{
static bool FindSubFolders(const std::string & sFolderToCheck,
std::vector< std::string > & vecSubFoldersFound);
}
In DLL file 2:
void aFunction()
{
std::vector<std::string> folders;
std::string sLocation;
...
abc::FindSubFolders(sLocation, folders)
}
In r开发者_如何学编程elease 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 DLL file 1's heap, but is being freed in DLL file 2.
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?
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 DLL files are compiled, make sure to use the Multi-threaded Debug DLL (/MDd) or Multi-threaded DLL (/MD) settings for the runtime library. That way, both DLL files 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 DLL files.
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 DLL files, the DLL files 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 DLL files, then they should be using the same heap and you can allocate in one DLL file and deallocate in another.
As other says, the problem can be solved by making sure that the CRT is shared between the two modules. But there are common scenarios where this contract is hard to enforce.
The reason is that making sure to link against a shared CRT will not work if the EXE and DLL do not link against the same CRT version (as in 6.0, 7.0, 8.0). For example if you take a DLL that has been built in VC6.0 and try to use it with an EXE build in VS2010 you will get the same issue as before. The two versions of CRT will be loaded in your process and will each use their own heap for allocation, regardless if your EXE and DLL use 'shared' CRT, they will not be the same.
A better practice for an API would be to make sure that objects allocated in one side are also destroyed on the same side. I know this sounds ugly but it is the only way to ensure that a DLL remains binary compatible.
This is only a problem if the application or one (or more) of the DLL files 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 files 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).
精彩评论