C ++ / CLI DLL mixed mode throws an exception on exit

I am having a problem with the C ++ / CLI mixed mode DLL I created. This throws an exception when unloading because the .NET application that uses it terminates. After executing DLL_PROCESS_DETACH , the DLL performs a cleanup of the runtime using the automatically registered functions atexit() / __onexit() and throws the following exception:

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

I traced the problem of calling atexit() , which is registered by the static exception object object get_static_exception_object() .

  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)* 

I use boost_1_47, statically linked for the most part, with the exception of boost :: thread, which is dynamically linked to avoid loaderlock. I also tried dynamically linking everything that didn't help. In addition, all forcing includes #pragma unmanaged blocks.

I hope someone had a similar problem or is he aware of a solution?

Thanks Mark

Here is the call stack just before the exception occurs:

 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 
+8
boost dll c ++ - cli mixed-mode atexit
source share
3 answers

I ran into the same problem and was able to track it to the following function in 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; } 

The problem part is here: static exception_ptr ep (...

You can simply remove the statics and it should work:

  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; } 

Notice how this function is used; it assigns the returned static variable to another static variable. The whole implementation of this function looks suspicious, maybe I will try to ask a question about enhanced support.

Other solutions to this problem may arise. A more detailed analysis of static variables in mixed assemblies can be found here: http://derevyanko.blogspot.com/2009/01/clic.html however only in Russian.

+8
source share

As described in a post on the Boost mailing list , one approach is to split the managed and unmanaged code into separate translation units (.cpp files and the headers they include #). Only Boost link from unmanaged translation units. Enable / clr for managed translation units only.

0
source share

You can add lines:

 #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 

before declaring get_static_exception_object and not include this file (or the boost header that includes this file) in your cli files.

For me, replacing one boost/thread.hpp with boost/thread/thread.hpp fixed the problem.

0
source share

All Articles