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

ato*_*erz 7 c++ dll exception-handling heap-corruption

我有一个原型函数,如下所示:

void function(std::string str);
Run Code Online (Sandbox Code Playgroud)

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

function("some string value here");
Run Code Online (Sandbox Code Playgroud)

从这个函数返回时,我得到堆损坏错误:

Windows已在program.exe中触发断点.

这可能是由于堆的损坏,这表示program.exe或它已加载的任何DLL中的错误.

这也可能是因为用户在program.exe具有焦点时按下F12.

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

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

bdo*_*lan 8

最有可能的是,你看到崩溃的原因是,在Windows中,DLL有自己的私有堆.

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

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

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


sas*_*alm 6

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

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

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


Big*_*oss 5

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