Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does memory allocated from inside a DLL become invalid after FreeLibrary()?

I had this bug today which turned out to be because I use a string allocated from inside my DLL after calling FreeLibrary().

This is a simple example reproducing the crash. This goes in DLL:

void dllFunc(char **output)
{
    *output = strdup("Hello"); // strdup uses malloc
}

This is in the EXE that loads the DLL:

void exeFunc()
{
    char *output;
    dllFunc(&output);
    std::string s1 = output; // This succeeds.
    FreeLibrary(dll);
    std::string s2 = output; // This crashes with access violation.
}

I read the documentation of FreeLibrary() but I couldn't find anything about memory becoming invalid after it's called.

Edit

I just realized that I had been using VS2008 toolchain for the DLL while using VS2010 toolchain for the EXE (I was using VS2010 as IDE for both, but you can select the toolchain from the project settings). Setting the toolchain to VS2010 for the DLL as well removed the crash.

like image 344
sashoalm Avatar asked Dec 15 '22 13:12

sashoalm


2 Answers

If you choose static linking with the MSVCRT (C Runtime) library, you will get the behavior you describe. Same thing also happens if your EXE and DLL are dynamically linked to an MSVCRT DLL, but are using different versions. Or if they are matched to the same version, but one is using DEBUG and the other is using RETAIL. In other words, memory is only as good as the lifetime of the MSVCRTxxx.dll used to make the allocation. I just saw your update to your question - yes, mixing and matching the CRT between VS 2008 and 2010 is the exact reason for the crash.

If both your DLL and EXE are dynamically linked to the same version of the MSVCRT DLL, then you share the memory heap and you avoid the problem you are having.

The standard practice is this: If your exported DLL function returns anything that needs to be "freed" or "released" later, then standard practice is to provide an additional function exported out of the DLL to handle de-allocations.

You can configure both the EXE and DLL's C Runtime linkage from the Code-Generation page for the C/C++ project settings in your project.

Picture here: http://imgur.com/uld4KYF.png

like image 153
selbie Avatar answered Apr 05 '23 23:04

selbie


This occurs because each Dll creates its own memory heap (which malloc and its C friends, along with new will use internally, generally via HeapAlloc), and when the Dll is freed, so is its heap.

Refer to this MSDN article for more Dll memory caveats. unless you are using a custom memory allocator, shared across all your binaries, you need to keep dynamically allocated memory within the module that created it (unless you can 100% guarantee that the object will not outlive its creator).

like image 22
Necrolis Avatar answered Apr 06 '23 01:04

Necrolis