I am having a problem with a C++/CLI mixed mode DLL that I created. It is throwing an exception when unloading as the .NET application that uses it exits. After DLL_PROCESS_DETACH
is executed, the DLL does runtime clean-up using automatically registered atexit() / __onexit()
functions and throws the following exception:
Unhandled exception at 0x752bb9bc (KernelBase.dll) in psstestm.exe:
0xC0020001: The string binding is invalid.
I've traced the problem to an atexit()
call which is registered by a static boost exception 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 am using boost_1_47 statically linked for the most part except boost::thread which is dynamically linked to avoid loaderlock. I've also tried dynamically linking all of boost which didn't help. Also all of the boost includes are surrounded by #pragma unmanaged
blocks.
I'm hoping someone has had a similar problem or knows 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
I have faced the same problem and managed to track it down 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 problematic part here is: static exception_ptr ep(...
You can just remove static 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;
}
Note how this function is used, it assigns returned static variable to another static variable. The whole implementation of this function looks suspicious, probably I will raise a question on boost support about this.
There are could be other workarounds to fix this issue. More analysis on static variables in mixed assemblies might be found here: http://derevyanko.blogspot.com/2009/01/clic.html however only in russian.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With