首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >MSVC调试堆断言跨二进制边界传递C++ STL对象

MSVC调试堆断言跨二进制边界传递C++ STL对象
EN

Stack Overflow用户
提问于 2022-10-28 23:41:01
回答 1查看 62关注 0票数 1

我们有一个主机应用程序和一个DLL,它们都是用相同的编译器设置构建的,都是使用静态CRT /MT构建的。(用VS2019和VS2022测试)

最后,我们传递一些包含两个STL对象的简单结构,例如

代码语言:javascript
运行
复制
struct MyData
{
    std::vector<std::string> entries;
};

...
MyData DLL::getMyData() const
{
    // ...
    return MyData();
}

当我们在主机应用程序端释放通过DLL的API检索到的MyData时,获取CRT堆断言。

代码语言:javascript
运行
复制
Debug Assertion Failed!

File: minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp
Line: 996

Expression: __acrt_first_block == header
代码语言:javascript
运行
复制
host.exe!free_dbg_nolock(void * const block, const int block_use) Line 996  C++
host.exe!_free_dbg(void * block, int block_use) Line 1030   C++
host.exe!operator delete(void * block) Line 38  C++
host.exe!operator delete(void * block, unsigned __int64 __formal) Line 32   C++
host.exe!std::_Deallocate<16,0>(void * _Ptr, unsigned __int64 _Bytes) Line 255  C++
host.exe!std::_Default_allocator_traits<std::allocator<std::_Container_proxy>>::deallocate(std::allocator<std::_Container_proxy> & _Al, std::_Container_proxy * const _Ptr, const unsigned __int64 _Count) Line 670 C++ 
host.exe!std::_Deallocate_plain<std::allocator<std::_Container_proxy>>(std::allocator<std::_Container_proxy> & _Al, std::_Container_proxy * const _Ptr) Line 976    C++
host.exe!std::_Delete_plain_internal<std::allocator<std::_Container_proxy>>(std::allocator<std::_Container_proxy> & _Al, std::_Container_proxy * const _Ptr) Line 989   C++
host.exe!std::string::~basic_string<char,std::char_traits<char>,std::allocator<char>>() Line 3007   C++
host.exe!DLL::MyData::~MyData() C++

奇怪的是,MSVC中的地址清除器(以及使用clang/Xcode的ASAN )没有报告错误,而且应用程序在发布版本中似乎是稳定的,但是在MSVC中,Debug构建总是在dtor中中断。

值得注意的是,这通常至少有一个调用站点远离DLL接口,那么在什么情况下,RVO将对象从DLL中移开而不复制它的二进制边界呢?在这件事上有点困惑。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-10-29 00:06:31

解决这个问题的最简单的方法通常是DLL导出MyData类(从内存中将dtor定义为虚拟也可以解决这个问题)。否则,由于dtor是内联的,因此您将得到dtor的两个副本,一个在原始DLL中,一个在exe中。DLL::getMyData()正在使用DLL中的堆创建一个新实例。然后,Exe试图使用自己的堆释放数据成员。MSVC然后发出一个错误,因为那个堆没有看到原始的分配。

对于std::string (或stdlib中的任何其他容器类型),我强烈建议至少使这些成员私有。如果程序员直接访问成员函数(例如保留),您很容易遇到同样的问题。

通常,MSVC会对此问题给出一个C4251警告。听起来这个警告可能已经在您的构建中被禁用了吗?

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74241837

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档