我曾经遇到过一个问题,当时我的应用程序表现得与你的类似。后来发现是sprintf中的一个严重缓冲区溢出。当然,在调试器附加的情况下它可以正常工作。我所做的就是安装了一个未处理异常过滤器(
SetUnhandledExceptionFilter),其中我只是无限地阻塞(使用等待单个对象函数WaitForSingleObject,等待一个虚假的句柄,并将超时值设置为INFINITE)。
所以你可以按照以下方式进行操作:
long __stdcall MyFilter(EXCEPTION_POINTERS *)
{
HANDLE hEvt=::CreateEventW(0,1,0,0);
if(hEvt)
{
if(WAIT_FAILED==::WaitForSingleObject(hEvt, INFINITE))
{
//log failure
}
}
}
// 在wmain/WinMain中的某个地方:
SetUnhandledExceptionFilter(MyFilter);
之后,在错误已经显现出来后再附加调试器(gui程序停止响应)。
然后,您可以立即拍摄转储文件并进行调试:
.dump /ma path_to_dump_file
或者直接调试。最简单的方法是跟踪运行时异常处理机制保存处理器上下文的位置:
s-d esp Range 1003f
该命令将搜索堆栈地址空间中的CONTEXT记录(提供搜索长度)。我通常使用类似于
'l?10000'的东西。请注意,不要使用过大的数字,因为您需要的记录通常靠近未处理的异常过滤器帧。
1003f是用于捕获处理器状态的标志组合(我认为它对应于CONTEXT_FULL)。
您的搜索将类似于下面这样:
0:000> s-d esp l1000 1003f
0012c160 0001003f 00000000 00000000 00000000 ?...............
一旦你得到了结果,就可以在cxr命令中使用地址:
.cxr 0012c160
这将带您进入这个新的CONTEXT,正好在崩溃时(您将在应用程序崩溃时得到完全的堆栈跟踪)。
此外,使用以下命令:
.exr -1
以确定发生了哪个异常。
希望能有所帮助。