【发布时间】:2011-09-18 20:40:29
【问题描述】:
我有一个大型应用程序,最近在调试器中运行时开始表现出相当奇怪的行为。一、基础:
OS: Windows 7 64-bit.
Application: Multithreaded VCL app with many dlls, bpls, and other components.
Compiler/IDE: Embarcadero RAD Studio 2010.
观察到的症状是:当调试器附加到我的应用程序时,某些任务会导致应用程序崩溃。细节更令人困惑:我的应用程序停止并显示一条 Windows 消息,“YourApplication 已停止工作”。它还提供了向 Microsoft 发送 minidump 的帮助。
需要注意的是:不附加调试器时应用程序不会崩溃。此外,调试器不会在应用程序运行时指示任何异常或其他问题。
设置和单步执行断点似乎会影响应用程序崩溃的点,但我怀疑这是调试线程而不是有问题的线程的症状。
这些崩溃也发生在我同事的计算机上,与我观察到的行为相同。这使我不怀疑在我的计算机上安装某些东西失败了。遇到此问题的同事也在运行 Windows 7 64 位。我没有同事没有遇到过这个问题。
我从崩溃中收集了一些经过分析的完整转储。我发现失败实际上每次都发生在同一个地方。这是来自转储的异常数据(它总是相同的,当然除了 ThreadId):
Exception Information
ThreadId: 0x000014C0
Code: 0x4000001F Unknown (4000001F)
Address: 0x773F2507
Flags: 0x00000000
NumberParameters: 0x00000001
0x00000000
Google 发现代码 0x4000001F 实际上是 STATUS_WX86_BREAKPOINT。 Microsoft 毫无帮助地将其描述为“Win32 x86 仿真子系统使用的异常状态代码”。
以下是堆栈详细信息(似乎没有变化):
0x773F2507: ntdll.dll+0x000A2507: RtlQueryCriticalSectionOwner + 0x000000E8
0x773F3DAB: ntdll.dll+0x000A3DAB: RtlQueryProcessLockInformation + 0x0000020D
0x773D2ED9: ntdll.dll+0x00082ED9: RtlUlonglongByteSwap + 0x00005C69
0x773F3553: ntdll.dll+0x000A3553: RtlpQueryProcessDebugInformationRemote + 0x00000044
0x74F73677: kernel32.dll+0x00013677: BaseThreadInitThunk + 0x00000012
0x77389F02: ntdll.dll+0x00039F02: RtlInitializeExceptionChain + 0x00000063
0x77389ED5: ntdll.dll+0x00039ED5: RtlInitializeExceptionChain + 0x00000036
值得注意的是,在 0x773F24ED 处似乎有一个函数 Epilog,这表明 RtlQueryCriticalSectionOwner 是一个红鲱鱼。同样,函数 Epilog 对 RtlQueryProcessLockInformation 产生了怀疑。 0x5C69 偏移量对 RtlUlonglongByteSwap 产生了怀疑。不过,其他符号看起来是合法的。
具体来说,RtlpQueryProcessDebugInformationRemote 看起来是合法的。网上有些人(http://www.cygwin.com/ml/cygwin-talk/2006-q2/msg00050.html)似乎认为它是由调试器创建的,用于收集调试信息。这个理论对我来说似乎是合理的,因为它似乎只在附加调试器时出现。
与往常一样,当某些事情发生故障时,某些变化会破坏它。在这种情况下,某些东西正在动态加载一个新的 dll。我可以通过不动态加载特定的 dll 来停止崩溃。我不相信 dll 加载是相关的,但这里有详细信息,以防万一:
dll源为C,以下是未设置为默认的编译选项:
Language Compliance: ANSI
Merge duplicate strings: True
Read-only strings: True
PCH usage: Do not use
Dynamic RTL: False
(项目选项说 False 是动态 RTL 的默认值,尽管在我创建 dll 项目时它被设置为 True。)
DLL 使用 LoadLibrary 加载并使用 FreeLibrary 释放。模块的加载和卸载似乎一切都很好。然而,在库被卸载后不久(使用 FreeLibrary),上述线程使程序崩溃。为了调试,我删除了对库的所有实际调用(包括,为了进行更多测试,DllMain)。调用或不调用、DllMain 或没有 DllMain 或其他任何东西的组合似乎都不会以任何方式改变崩溃的行为。简单地加载和卸载 dll 会在稍后调用崩溃。
此外,将 dll 更改为使用动态 RTL 也会导致调试器线程崩溃停止。这是不可取的,因为编译的 dll 在没有 CodeGear Runtime 可用的情况下确实应该可用。此外,dll 的大小也很重要。 dll 中包含的 C 代码不使用任何库。 (它不包括头文件,甚至标准库头文件。没有 malloc/free,没有 printf,什么都没有。它只包含完全依赖于其输入且不需要动态分配的函数。)它也是不可取的,因为“修复”a通过改变东西直到它工作而不理解它为什么工作的错误真的不是一个好计划。 (这往往会导致错误重现和奇怪的编码习惯。但实际上,在这一点上,如果我找不到其他任何东西,我可能会承认这一点失败。)
最后,我的问题可能与以下问题之一有关:
- System error after debugging multithreaded applications
- Program and debugger quit without indication of problem
任何想法或建议将不胜感激。
【问题讨论】:
-
卸载DLL后线程是否自行终止?如果是这样,您应该调用 FreeLibraryAndExitThread 而不是进行两次不同的调用。此外,您是否为 DLL 和应用程序的运行时库使用多线程调试 (/MTd)?
-
对前者,没有。 DLL 在主线程中加载和卸载。到第二个,我想是的。
-
这是一个难题。似乎问题出在 C 运行时库启动代码中。确保 C++Builder 没有在某些库/包中静态链接。链接器的命令行参数是什么?我不得不解决 TChart 启动代码中的错误(在调用 main 函数之前)。好痛啊……
标签: c++ exception dll c++builder c++builder-2010