【问题标题】:Mixed-mode C++/CLI DLL throws exception on exit混合模式 C++/CLI DLL 在退出时抛出异常
【发布时间】:2011-12-29 23:40:21
【问题描述】:

我创建的 C++/CLI 混合模式 DLL 有问题。当使用它的 .NET 应用程序退出时,它会在卸载时引发异常。执行DLL_PROCESS_DETACH 后,DLL 使用自动注册的atexit() / __onexit() 函数进行运行时清理并抛出以下异常:

Unhandled exception at 0x752bb9bc (KernelBase.dll) in psstestm.exe: 
0xC0020001: The string binding is invalid.

我已将问题追溯到由静态提升异常对象get_static_exception_object() 注册的atexit() 调用。

    function_to_call    0x0f560410 _t2m@???__Fep@?1???$get_static_exception_object@Ubad_exception_@exception_detail@boost@@@exception_detail@boost@@YA?AVexception_ptr@1@XZ@YAXXZ@?A0x0a546e27@@YAXXZ   void (void)*

我使用的 boost_1_47 大部分都是静态链接的,除了 boost::thread 是动态链接以避免加载程序锁定。我也尝试过动态链接所有没有帮助的提升。此外,所有的提升包括都被#pragma unmanaged 块包围。

我希望有人遇到过类似的问题或知道解决方案吗?

谢谢,马克

这是异常发生前的调用堆栈:

psscorem.dll!_CRT_INIT(void * hDllHandle=0x0f4b0000, unsigned long dwReason=0, void * lpreserved=0x00000001)  Line 413  C
psscorem.dll!__DllMainCRTStartup(void * hDllHandle=0x0f4b0000, unsigned long dwReason=0, void * lpreserved=0x00000001)  Line 526 + 0x11 bytes   C
psscorem.dll!_DllMainCRTStartup(void * hDllHandle=0x0f4b0000, unsigned long dwReason=0, void * lpreserved=0x00000001)  Line 476 + 0x11 bytes    C
mscoreei.dll!__CorDllMain@12()  + 0xde bytes    
mscoree.dll!_ShellShim__CorDllMain@12()  + 0xad bytes   
ntdll.dll!_LdrpCallInitRoutine@16()  + 0x14 bytes   
ntdll.dll!_LdrShutdownProcess@0()  + 0x141 bytes    
ntdll.dll!_RtlExitUserProcess@4()  + 0x74 bytes 
kernel32.dll!749479f5()     
mscoreei.dll!RuntimeDesc::ShutdownAllActiveRuntimes()  + 0xc8 bytes 
mscoreei.dll!CLRRuntimeHostInternalImpl::ShutdownAllRuntimesThenExit()  + 0x15 bytes    
clr.dll!EEPolicy::ExitProcessViaShim()  + 0x66 bytes    
clr.dll!SafeExitProcess()  + 0x99 bytes 
clr.dll!DisableRuntime()  - 0x1146bb bytes  
clr.dll!EEPolicy::HandleExitProcess()  + 0x57 bytes 
clr.dll!__CorExeMainInternal@0()  + 0x11c bytes 
clr.dll!__CorExeMain@0()  + 0x1c bytes  
mscoreei.dll!__CorExeMain@0()  + 0x38 bytes 
mscoree.dll!_ShellShim__CorExeMain@0()  + 0x227 bytes   
mscoree.dll!__CorExeMain_Exported@0()  + 0x8 bytes  
kernel32.dll!@BaseThreadInitThunk@12()  + 0x12 bytes    
ntdll.dll!___RtlUserThreadStart@8()  + 0x27 bytes   
ntdll.dll!__RtlUserThreadStart@8()  + 0x1b bytes    

【问题讨论】:

    标签: dll boost c++-cli mixed-mode atexit


    【解决方案1】:

    我遇到了同样的问题,并设法将其追溯到 exception_ptr.hpp 中的以下函数:

        template <class Exception>
        exception_ptr
        get_static_exception_object()
            {
            Exception ba;
            exception_detail::clone_impl<Exception> c(ba);
            c <<
                throw_function(BOOST_CURRENT_FUNCTION) <<
                throw_file(__FILE__) <<
                throw_line(__LINE__);
            static exception_ptr ep(shared_ptr<exception_detail::clone_base const>(new exception_detail::clone_impl<Exception>(c)));
            return ep;
            }
    

    这里有问题的部分是:static exception_ptr ep(...

    您可以删除静态,它应该可以工作:

        template <class Exception>
        exception_ptr
        get_static_exception_object()
            {
            Exception ba;
            exception_detail::clone_impl<Exception> c(ba);
            c <<
                throw_function(BOOST_CURRENT_FUNCTION) <<
                throw_file(__FILE__) <<
                throw_line(__LINE__);
            exception_ptr ep(shared_ptr<exception_detail::clone_base const>(new exception_detail::clone_impl<Exception>(c)));
            return ep;
            }
    

    注意这个函数是如何使用的,它将返回的静态变量分配给另一个静态变量。这个函数的整个实现看起来很可疑,可能我会提出一个关于提升支持的问题。

    可能还有其他解决方法可以解决此问题。更多关于混合程序集中的静态变量的分析可以在这里找到:http://derevyanko.blogspot.com/2009/01/clic.html 但是只有俄语版本。

    【讨论】:

    • 谢谢!!!我一直在追踪这件事。我不太了解 C++,无法理解这如何导致调用 atexit。
    【解决方案2】:

    如post on the Boost mailing list 中所述,一种方法是将托管代码和非托管代码分离为单独的翻译单元(.cpp 文件和它们#include 的标头)。仅从非托管翻译单元引用 Boost。仅为托管翻译单元打开 /clr。

    【讨论】:

      【解决方案3】:

      您可以添加行:

      #if _MANAGED
      #error "Don't include that file in CLI compilation units. It will cause failure when cleaning the static objects of the managed dll"
      #endif
      

      在声明 get_static_exception_object 之前,不要在 cli 文件中仅包含该文件(或包含该文件的 boost 标头)。

      对我来说,用boost/thread/thread.hpp 替换一个boost/thread.hpp 解决了这个问题。

      【讨论】:

        猜你喜欢
        • 2010-12-13
        • 1970-01-01
        • 2011-02-11
        • 1970-01-01
        • 2015-11-02
        • 2011-07-03
        • 1970-01-01
        • 2013-09-05
        • 2013-05-24
        相关资源
        最近更新 更多