不完全确定我已经确定了这个问题,但是这里是我所看到的和我所想的 。
我有一个主要用C语言编写的加载C ++ DLL的Win32程序。 该DLL通过COM对象将C程序中的数据传递给另一个应用程序 – 这可能是由DLL本身实例化的。 至lessWindows XP和Windows 7(可能是Win95和Win98,我需要更深入地回顾代码历史logging以了解何时引入此接口),但是在Windows 10中,程序崩溃在FreeLibrary()调用此DLL期间。
在debugging器中检查这个时,DLL_DETACH_PROCESS似乎被成功处理(处理该消息时没有执行代码)。 崩溃发生在离开入口点的代码之后(或同时)。
如果我继续步入,我最终在一个名为utilcls.h,这似乎是Borland C Builder 6头文件之一的头文件。 我相信其中的模板代码与COM对象被拆除有关。 一个Unbind()调用会通过,这是在崩溃之前我可以进入的最后一行代码。
出于虚拟内存地址空间(Borland C ++ Builder 6程序)
MessageBox“exception程序终止”让我的应用程序继续运行
除以零会导致Borland C ++中的内存泄漏
如果我使用debugging器的cpu窗口并继续步进,那么在崩溃到来之前,所有剩下的事情似乎都与释放内存有关,但是到了那里,cpu执行了很多步骤。
崩溃引发APPCRASHexception0xc0000602,指的是Combase.dll。
简单地说,不要为FreeLibrary调用这个DLL就可以让应用程序成功closures,但我的假设是FreeLibrary调用很重要。
COM对象在FreeLibrary()调用之前由数据共享应用程序释放,从而允许该应用程序closures。 我目前的假设是,这种不连贯的一些在新的操作系统中发生了不同的事情,这导致了崩溃,但是我不知道如何被发现。
我的问题:
如果对其他人更了解他们正在做的事情是显而易见的,那么导致这次事故的原因是什么?
试图进行debugging的下一步是什么? 我已经用尽了我所使用的debugging环境的知识,不知道COM或DLL是否足够了解下一个要问的问题。
一些debugging器输出RbMm请求:
0:000:x86> t ntdll_77b40000!RtlIsCriticalSectionLockedByThread+0x1b: 77b7256b c20400 ret 4 0:000:x86> t combase!DecrementMTAUsageHelper+0x5b: 7527a2d6 85c0 test eax,eax 0:000:x86> r eax eax=00000001 0:000:x86> t combase!DecrementMTAUsageHelper+0x5d: 7527a2d8 0f859a000000 jne combase!DecrementMTAUsageHelper+0xfd (7527a378) [br=1] 0:000:x86> t combase!DecrementMTAUsageHelper+0xfd: 7527a378 e89e9e0f00 call combase!CrashProcessWithWERReport (7537421b)
在这一点上,堆栈看起来大致如下:
ChildEBP RetAddr Args to Child 0019f9b8 7527a37c 063f4248 753d8448 00000000 combase!CrashProcessWithWERReport+0x35 0019f9e8 75292bfc 753d8448 7529257e 00000000 combase!DecrementMTAUsageHelper+0x101 (Inline) -------- -------- -------- -------- combase!DecrementMTAUsage+0x9 0019f9f0 7529257e 00000000 00000000 00000000 combase!CDllHost::MTAUninitializeApartmentOnly+0xe 0019fa08 7527543a 00000000 063f4248 00712410 combase!CDllHost::ClientCleanupFinish+0x4d 0019fa30 75276361 00000000 0019fa8c 00000000 combase!DllHostProcessUninitialize+0xa0 0019fa58 7527a452 000d06f6 00712410 00000000 combase!ApartmentUninitialize+0xe4 0019fa70 752c2a1e 000d06f6 00712e18 00712e80 combase!wCoUninitialize+0xd0 0019fa94 74ed3e58 00000003 74c17ff1 a6d0e607 combase!CoUninitialize+0x7e 0019fa9c 74c17ff1 a6d0e607 000b0792 74ed48f0 imm32!CtfImmCoUninitialize+0x48 0019fb7c 74809ea6 00050004 000d06f6 00000000 msctf!TF_Notify+0x581 0019fb98 748080dc 00050004 000d06f6 00000000 user32!CtfHookProcWorker+0x36 0019fbe0 74807fa6 0019fc34 0019fc24 00000000 user32!CallHookWithSEH+0x5c 0019fc08 77bb0006 0019fc24 00000018 0019fc80 user32!__fnHkINDWORD+0x26 0019fc38 710623fb 000b0792 04ff11aa 05480e70 ntdll!KiUserCallbackdispatcher+0x36 0019fc50 050364e4 000b0792 050376d8 05480e70 apphelp!DWM8AND16BitHook_DestroyWindow+0x2b 0019fc8c 05051007 00000000 05055034 00000001 myDLL!myCOMObject_tlbFinalize+0x408a4 0019fcb4 050511c6 0019fcd0 00000001 04ff1318 myDLL!myCOMObject_tlbFinalize+0x5b3c7 0019fcd8 04ff13d3 05055034 77badcce 04ff0000 myDLL!myCOMObject_tlbFinalize+0x5b586 0019fd00 77b807c6 04ff1318 04ff0000 00000000 myDLL+0x13d3 0019fd50 77b6aa5e 00000000 00000000 259704e5 ntdll!LdrpCallInitRoutine+0x43 0019fdb8 77b6e6c8 00000000 0071dd60 00000000 ntdll!LdrpProcessDetachNode+0xbb 0019fdd8 77b6e5af 25970745 0071e560 c000022d ntdll!LdrpUnloadNode+0x100 0019fe18 77b6e4f6 004afcc4 004ae3a4 04ff0000 ntdll!LdrpDecrementModuleLoadCountEx+0xa7 0019fe38 746e9d56 04ff0000 006e33c5 00000000 ntdll!LdrUnloadDll+0x86 0019fe4c 0049261c 04ff0000 00000000 00493034 KERNELBASE!FreeLibrary+0x16 0019fe64 00441895 004afc98 fffffffe 0019fee8 rpopdbg!_GetExceptDLLinfo+0x914bf
现在rest,但我的猜测是我需要弄清楚如何正确清理COM对象? 也许在响应DLL_DETACH_PROCESS?
崩溃引发APPCRASH异常0xc0000602,指的是Combase.dll
combase.dll使用0xc0000602 ( STATUS_FAIL_FAST_EXCEPTION )代码
void CrashProcessWithWERReport();
(这个代码调用了RaiseFailFastException )
CrashProcessWithWERReport仅在2种情况下调用DecrementMTAUsageHelper – CoDecrementMTAUsage调用次数多于CoIncrementMTAUsage或者( 我几乎可以肯定的是这个原因 )当调用线程保持Loader临界区时调用的DecrementMTAUsageHelper CoIncrementMTAUsage – 所以在DLL加载或卸载过程中。 从MSDN
在进程关闭或dllmain内不要调用CoDecrementMTAUsage 。 您可以在调用之前调用CoDecrementMTAUsage来启动关机过程。
所以我的猜测 – 一些代码调用CoDecrementMTAUsage在你的DLL卸载过程中(当你调用FreeLibrary )
你的DLL不能直接调用CoIncrementMTAUsage / CoDecrementMTAUsage因为这个新的API,存在从win 8开始(也请检查你的代码在win 8.1上 – 我想也会崩溃),但是这个api可以间接从其他系统组件中调用。
我可以假设你的DLL不直接释放一些使用过的资源,或者当DLL仍然持有一些资源时调用FreeLibrary (所以你调用FreeLibrary没有对DLL进行适当的清理调用),并且结果这个资源在卸载过程中开始释放( CoDecrementMTAUsage )
试图进行调试的下一步是什么?
你需要使用调试符号文件(比如winDbg)。 在DecrementMTAUsageHelper , CoDecrementMTAUsage设置断点,并可能是CoIncrementMTAUsage – 我正确的调用RtlIsCriticalSectionLockedByThread返回TRUE (这个API从DecrementMTAUsageHelper开始调用)。
在任何情况下在DecrementMTAUsageHelper调用点(在崩溃之前)发布线程调用堆栈,并且也可能在CoIncrementMTAUsage上CoIncrementMTAUsage
———————-编辑————————-
通过查看堆栈跟踪可见,您的DLL从DllMain调用DestroyWindow 。
apphelp!DWM8AND16BitHook_DestroyWindow
获取DLL_PROCESS_DETACH通知的线程不一定是得到DLL_PROCESS_ATTACH通知的线程。 您不能在DLL_PROCESS_ATTACH或DLL_PROCESS_DETACH处理程序中使用线程关联来执行任何操作,因为您无法保证将调用哪个线程来处理这些进程通知。 这个经典的例子,我被告知开发者支持团队以惊人的频率运行,是一个DLL,它在DLL_PROCESS_ATTACH处理程序中创建一个窗口,并在DLL_PROCESS_DETACH处理程序中销毁该窗口。
但是由于另外一个原因你的崩溃在这篇文章中没有列出–DllMain有很多限制 ,里面什么都不能调用。 尽管DestroyWindow没有直接在这里列出,但作为显示你的情况 – 这是非法调用(即使我们调用相同的线程,在这个窗口创建) – 当你的窗口被破坏imm32.CtfImmNotify(msctf!TF_Notify)被称为
0019fa9c 74c17ff1 a6d0e607 000b0792 74ed48f0 imm32!CtfImmCoUninitialize+0x48 0019fb7c 74809ea6 00050004 000d06f6 00000000 msctf!TF_Notify+0x581 0019fb98 748080dc 00050004 000d06f6 00000000 user32!CtfHookProcWorker+0x36 0019fbe0 74807fa6 0019fc34 0019fc24 00000000 user32!CallHookWithSEH+0x5c
结果从DllMain调用 CoUninitialize !
从MSDN
不要从DllMain函数调用CoInitialize,CoInitializeEx或CoUninitialize。
这里面的FINAL CoUninitialize里面调用了DecrementMTAUsage ,通过调用RtlIsCriticalSectionLockedByThread和CrashProcessWithWERReport来确定我们里面的loader加载器被锁定了。
解决方案
当然最好的是修复DLL,但如果这是不可能的 – 认为下一个“黑客”将是工作
HRESULT hr = CoInitialize(0); // asume that we in STA FreeLibrary(hDLL); if (0 <= hr) CoUninitialize();
这个CoUninitialize当然imm32!CtfImmCoUninitialize会被imm32!CtfImmCoUninitialize调用,但是这不会是最终的初始化,并且结果是DecrementMTAUsage不会被调用
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。