为什么在FreeLibrary()之后从DLL内部分配的内存变得无效?

时间:2013-03-08 18:28:04

标签: c++ winapi dll dynamic-memory-allocation

我今天遇到了这个错误,原因是我在调用FreeLibrary()后使用了一个字符串从我的DLL中分配

这是复制崩溃的简单示例。这是在DLL中:

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

这是在加载DLL的EXE中:

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

我阅读了FreeLibrary()的文档,但是在调用后,我找不到任何关于内存变得无效的内容。

修改

我刚刚意识到我在使用VS2010工具链进行EXE时一直使用VS2008工具链(我使用VS2010作为IDE的两者,但你可以从项目设置中选择工具链)。为DLL设置工具链到VS2010也删除了崩溃。

2 个答案:

答案 0 :(得分:6)

如果选择与MSVCRT(C运行时)库的静态链接,您将获得您描述的行为。如果您的EXE和DLL动态链接到MSVCRT DLL,但使用的是不同版本,也会发生同样的情况。或者如果它们匹配相同的版本,但是一个使用DEBUG而另一个使用RETAIL。换句话说,内存只能与用于进行分配的MSVCRTxxx.dll的生命周期一样好。我刚刚看到你对你的问题的更新 - 是的,混合和匹配VS 2008和2010之间的CRT是崩溃的确切原因。

如果您的DLL和EXE都动态链接到MSVCRT DLL的相同版本,那么您可以共享内存堆,从而避免出现问题。

标准做法是:如果导出的DLL函数返回需要稍后“释放”或“释放”的任何内容,那么标准做法是提供从DLL导出的附加函数来处理取消分配。 / p>

您可以从代码生成页面为项目中的C / C ++项目设置配置EXE和DLL的C运行时链接。

图片来源:http://imgur.com/uld4KYF.png

答案 1 :(得分:5)

这是因为每个Dll创建自己的内存堆(malloc及其C朋友和new将在内部使用,通常通过HeapAlloc),当Dll是自由,它的堆也是如此。

有关更多Dll内存警告,请参阅this MSDN article。除非您使用在所有二进制文件中共享的自定义内存分配器,否则您需要在创建它的模块中保留动态分配的内存(除非您可以100%保证该对象不会超过其创建者)。