我之前问过一个 boost-interprocess 问题,并发誓我会停止使用它,但是,唉,我被困住了,我真的需要这个东西才能工作。所以我还在和它抗争。
我在分配然后立即销毁 a 时遇到了奇怪的崩溃,boost::interprocess::managed_windows_shared_memory::segment_manager
但它只发生在我正在构建的 Windows DLL 项目中。我试图在一个独立的程序中重现它作为向 Boost 报告的一种方式,但它不会在我自己的 DLL 之外重现。
当我正常创建对象并在更理智的时间释放它时也会发生这种情况,但我想在这里展示的是 Boost 能够创建一个对象,并且没有时间过去,也没有任何状态在堆,但 Boost 无法在不崩溃的情况下释放该对象。
这不会发生在一个独立的示例项目中(我构建了一个,只是为了看看它是否会),但是,我知道没有其他代码在它崩溃的项目中运行。
真正奇怪的是它从 DLLMain 函数中崩溃了,而 DLLMain 函数中的第一件事就是分配然后销毁这个 C++ boost 对象。这个 boost 对象有点奇怪,它创建了很多东西(红黑树),然后甚至无法清理自己。
下面的代码几乎但还不足以重现该问题。我的 DLL 有问题,导致生成的 Boost 对象能够自行创建,但它们在关机时崩溃:
// BoostDllMain.cpp :
//
// Attempt to demonstrate an insane situation in my code, where
// boost::interprocess::managed_windows_shared_memory::segment_manager
// can be created, but freeing it causes access violations. The context
// for object creation and destruction is DLL load and unload time.
#include "stdafx.h"
#include <objbase.h>
#include <windows.h>
#ifdef PERSISTENT_SHARED_MEM
#include <boost/interprocess/managed_shared_memory.hpp>
#else
#include <boost/interprocess/managed_windows_shared_memory.hpp>
#endif
#include <boost/interprocess/containers/map.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <functional>
#include <utility>
#define SHARED_AREA_SIZE (1024*1024*8) // 8 megabytes of shared memory should be enough to store more than 60K data points.
// In testing using current structure sizes, allocation Failed at the 61678th
// data point item when set to this value.
#ifdef PERSISTENT_SHARED_MEM
typedef boost::interprocess::managed_shared_memory mgr;
typedef boost::interprocess::managed_shared_memory::segment_manager seg;
#else
typedef boost::interprocess::managed_windows_shared_memory mgr;
typedef boost::interprocess::managed_windows_shared_memory::segment_manager seg;
#endif
using namespace boost::interprocess;
mgr * segment1;
mgr * segment2;
void Init(void) {
// Tweak C Runtime Debug Heap Flags.
int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
tmpFlag |= _CRTDBG_LEAK_CHECK_DF;
tmpFlag |= _CRTDBG_CHECK_CRT_DF;
_CrtSetDbgFlag( tmpFlag );
segment1 = new mgr( open_or_create
, "ED3_MEMORY" // This is a global memory area name
, SHARED_AREA_SIZE );
segment2 = new mgr( open_or_create
, "ED3_MEMORY" // This is a global memory area name
, SHARED_AREA_SIZE );
}
void Cleanup(void) {
delete segment1;
segment1 = NULL;
delete segment2;
segment2 = NULL;
}
//
extern "C"
BOOL WINAPI DllMain(IN HANDLE hInstance, IN DWORD dwReason, IN VOID *pReserved )
{
switch ( dwReason )
{
case DLL_PROCESS_ATTACH:
Init();
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
Cleanup();
break;
default:
break;
}
return(1);
}
简而言之,managed_windows_shared_memory
无论您创建什么对象,甚至都不能立即彻底销毁(没有访问冲突),这就是我在上面试图展示的内容,我在 DLL 加载时创建对象,并在 DLL 时销毁它卸载。
这是一个堆栈回溯。如果你能理解它,你可能是一个 C++ 编译器,而不是一个人,但无论如何,这里是:
> mydll.dll!boost::interprocess::offset_ptr<boost::intrusive::compact_rbtree_node<boost::interprocess::offset_ptr<void,int,unsigned int,0> >,int,unsigned int,0>::offset_ptr<boost::intrusive::compact_rbtree_node<boost::interprocess::offset_ptr<void,int,unsigned int,0> >,int,unsigned int,0>(const boost::interprocess::offset_ptr<boost::intrusive::compact_rbtree_node<boost::interprocess::offset_ptr<void,int,unsigned int,0> >,int,unsigned int,0> & ptr={...}) Line 272 + 0xf bytes C++
mydll.dll!boost::intrusive::compact_rbtree_node_traits_impl<boost::interprocess::offset_ptr<void,int,unsigned int,0> >::get_left(const boost::interprocess::offset_ptr<boost::intrusive::compact_rbtree_node<boost::interprocess::offset_ptr<void,int,unsigned int,0> >,int,unsigned int,0> & n={...}) Line 142 + 0x1d bytes C++
mydll.dll!boost::intrusive::detail::tree_algorithms<boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1> >::dispose_subtree<boost::intrusive::detail::node_disposer<boost::intrusive::detail::null_disposer,boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> > > >(boost::interprocess::offset_ptr<boost::intrusive::compact_rbtree_node<boost::interprocess::offset_ptr<void,int,unsigned int,0> >,int,unsigned int,0> x={...}, boost::intrusive::detail::node_disposer<boost::intrusive::detail::null_disposer,boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> > > disposer={...}) Line 1298 + 0xd bytes C++
mydll.dll!boost::intrusive::detail::tree_algorithms<boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1> >::clear_and_dispose<boost::intrusive::detail::node_disposer<boost::intrusive::detail::null_disposer,boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> > > >(const boost::interprocess::offset_ptr<boost::intrusive::compact_rbtree_node<boost::interprocess::offset_ptr<void,int,unsigned int,0> >,int,unsigned int,0> & header={...}, boost::intrusive::detail::node_disposer<boost::intrusive::detail::null_disposer,boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> > > disposer={...}) Line 577 + 0x15 bytes C++
mydll.dll!boost::intrusive::rbtree_algorithms<boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1> >::clear_and_dispose<boost::intrusive::detail::node_disposer<boost::intrusive::detail::null_disposer,boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> > > >(const boost::interprocess::offset_ptr<boost::intrusive::compact_rbtree_node<boost::interprocess::offset_ptr<void,int,unsigned int,0> >,int,unsigned int,0> & header={...}, boost::intrusive::detail::node_disposer<boost::intrusive::detail::null_disposer,boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> > > disposer={...}) Line 451 + 0x16 bytes C++
mydll.dll!boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> >::clear_and_dispose<boost::intrusive::detail::null_disposer>(boost::intrusive::detail::null_disposer disposer={...}) Line 1006 + 0x26 bytes C++
mydll.dll!boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> >::clear() Line 987 C++
mydll.dll!boost::intrusive::detail::clear_on_destructor_base<boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> > >::~clear_on_destructor_base<boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> > >() Line 27 C++
mydll.dll!boost::intrusive::rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> >::~rbtree_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> >() Line 284 + 0x14 bytes C++
mydll.dll!boost::intrusive::set_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> >::~set_impl<boost::intrusive::setopt<boost::intrusive::detail::base_hook_traits<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int>,boost::intrusive::rbtree_node_traits<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,1,boost::intrusive::default_tag,3>,std::less<boost::interprocess::ipcdetail::intrusive_value_type_impl<boost::intrusive::detail::generic_hook<boost::intrusive::get_set_node_algo<boost::interprocess::offset_ptr<void,int,unsigned int,0>,1>,boost::intrusive::default_tag,1,3>,char,unsigned int> >,unsigned int,1> >() Line 139 + 0x14 bytes C++
mydll.dll!boost::interprocess::iset_index<boost::interprocess::ipcdetail::index_config<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,int,unsigned int,0>,0> > >::~iset_index<boost::interprocess::ipcdetail::index_config<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,int,unsigned int,0>,0> > >() + 0x14 bytes C++
mydll.dll!boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,int,unsigned int,0>,0>,boost::interprocess::iset_index>::header_t::~header_t() + 0x3d bytes C++
mydll.dll!boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,int,unsigned int,0>,0>,boost::interprocess::iset_index>::~segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,int,unsigned int,0>,0>,boost::interprocess::iset_index>() + 0x3d bytes C++
mydll.dll!boost::interprocess::segment_manager<char,boost::interprocess::rbtree_best_fit<boost::interprocess::mutex_family,boost::interprocess::offset_ptr<void,int,unsigned int,0>,0>,boost::interprocess::iset_index>::`scalar deleting destructor'() + 0x14 bytes C++
简而言之,我有
A. 从我编写的代码中排除了堆损坏,因为还没有其他代码在这个 DLL 的上下文中运行。可以创建和释放其他对象,没问题,只有这个Boost对象不能在这个DLL中创建或销毁。
B. DLL 项目正在编译,代码生成设置为“多线程调试 DLL”。
C. 析构函数 boost::interprocess::managed_windows_shared_memory::segment_manager
总是在同一个地方崩溃,无论如何它都不是随机的。那个地方是mydll.dll!boost::interprocess::offset_ptr<boost::intrusive::compact_rbtree_node<...
。
D. 如果我在这个 DLL 上下文中从 Windows 共享内存切换到另一个选项,仅称为,它会在 WMI 调用shared_memory
中冻结/死锁。get_last_bootup_time
这是一个来自 win32_api.hpp 的函数,它执行 Window WMI 函数调用并试图读取类Win32_OperatingSystem
属性LastBootUpTime
。
E. 我开始认为 DLL 和 Boost 彼此不喜欢,因为奇怪的奇怪原因,可能涉及CoInitialize
, 和黑暗的黑魔法。
你如何调试这么疯狂的东西?