从dll中的函数返回时堆损坏

时间:2012-12-03 07:48:09

标签: c++ dll exception-handling heap-corruption

我有一个如下原型的函数:

void function(std::string str);

在我的main函数中,在另一个加载和使用该dll的程序中调用此函数。

function("some string value here");

从此函数返回时,我收到堆损坏错误:

  

Windows在program.exe中触发了断点。

     

这可能是由于堆的损坏,这表明存在错误   program.exe或它加载的任何DLL。

     

这也可能是由于用户在按下F12时   program.exe具有焦点。

     

输出窗口可能包含更多诊断信息。

玩弄我的代码我发现了一些奇怪的意见:
1.当传入的字符串长度小于11个字符时,我没有错误,只要我添加更多字符就会出现错误。
2.将参数类型从std::string更改为std::string&时,错误消失。传递参考的想法来自here 我已经评论了这个功能的主体。那里的操作与产生的例外无关 4.将参数类型从std::string更改为char*也可以解决问题 可能导致此错误的原因是什么?我该如何解决?

3 个答案:

答案 0 :(得分:8)

最有可能的是,由于在Windows中,DLL拥有自己的私有堆这一事实,您会看到崩溃。

编译函数时,编译器为std::string的析构函数生成了一些代码,以清理它的参数。此代码释放DLL堆上分配的内存。但是,应用程序EXE还为std::string的构造函数生成自己的代码,该代码在程序堆上分配代码。当您在一个堆上分配并在另一个堆上释放时,会发生未定义的行为,并且您将崩溃。

至于为什么小字符串不会触发错误 - 许多std::string实现将小字符串内联到结构本身,以避免堆开销。当你的字符串足够小以适应时,不需要进行内存分配,因此它似乎正常工作......只要你对EXE和DLL使用相同的STL版本,并且内联的阈值永远不会改变。

要避免此问题,请不要按值将对象传递给DLL(除非它们是POD objects),并且不要释放不同于其创建的DLL或EXE中的对象。避免传递STL或C ++库对象,因为它们的实现可能在C ++编译器的不同版本之间有所不同。传递POD对象或C基元类型,例如const char *

答案 1 :(得分:6)

导出DLL函数时,最好只接受整数数据类型,即int或指针(不确定float和double)。

当你需要传递一个字符串时,将它作为const char *传递,当你需要DLL函数返回一个字符串时,向{DLL}传递指向预分配缓冲区的char *指针, DLL将写入字符串。

永远不要在DLL自己的函数之外使用DLL分配的内存,也不要传递具有自己的构造函数/析构函数的值结构。

答案 2 :(得分:5)

可能您已经与C运行时的静态版本链接,创建与C运行时的静态版本链接的DLL永远不是一个好主意。这可能会导致许多问题,例如在您的程序中,您的EXE从与其链接的静态C运行库的私有堆中分配内存,然后在您的DLL中要删除该堆并创建新堆(因为您要添加输入字符串的一些数据,它需要增加其缓冲区),因此会导致错误。最简单的方法是将程序的所有部分(EXE和DLL)与C ++运行时的DLL版本链接起来,这样它们都可以从MSVCRTXX.dll共享相同的堆