2

我之前问过一个 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, 和黑暗的黑魔法。

你如何调试这么疯狂的东西?

4

1 回答 1

3

DllMain 有一些非常严格的限制,因为您在进入此函数时持有加载程序锁,并且如果您在 DllMain 中加载库,库加载器将无法正确计算库依赖关系。

所有这一切真正棘手的部分是您不能直接或间接地持有加载程序锁。例如:不能调用LoadLibrary,不能与其他线程同步,不能调用CreateThread,不能从CRT调用内存管理函数,不能从User32调用任何东西。请在此处阅读 DLL 最佳实践指南(Microsoft),并查看文档末尾的参考资料。

简短的回答:不要在 DllMain 中加载这些东西。

于 2013-06-18T23:01:59.133 回答