delphi – 如何调试难以重现的崩溃,没有有用的调用堆栈?

我遇到了一个奇怪的崩溃在我们的软件,我有很多麻烦调试它,所以我正在寻求SO的建议如何解决它.

崩溃是读取NULL指针的访问冲突:

First chance exception at $00CF0041.
Exception class $C0000005 with message
‘access violation at 0x00cf0041: read
of address 0x00000000’.

它只发生“有时” – 我没有设法找出任何韵律或理由,但是,当时 – 只有在主线程.发生时,调用堆栈包含一个不正确的条目:

对于主线程,这是它应该显示一个大堆栈其他项目.

此时,所有其他线程都处于非活动状态(主要坐在WaitForSingleObject或类似的函数中).我只看到这个崩溃发生在主线程中.它总是具有相同的一个条目的调用堆栈,在相同的方法在相同的地址.这种方法可能或可能不相关 – 我们在我们的应用程序中使用VCL.但是,我敢打赌的是,事情(可能在很久以前)正在破坏堆栈,而崩溃的地址是有效的随机的.注意,它已经是多个构建的同一个地址,但它可能不是真正随机的.

这是我试过的:

试图在某一点上可靠地再现它.我没有发现每次都复制它,偶尔做的事情,或者没有,没有明显的理由.这些并不是足够狭窄的动作来将其缩小到特定的代码段.它可能与时间相关,但是在IDE突破的时候,其他线程通常什么都不做.我不能排除线程问题,但认为这是不可能的.
>使用额外的调试语句构建(额外的调试信息,额外的断言等)这样做后,崩溃永远不会发生.
>建立与Codeguard启用.这样做之后,崩溃就不会发生,Codeguard没有显示任何错误.

我的问题:

1.如何找到导致崩溃的代码?我如何做相当于走回来堆栈?

2.你有什么一般的建议来解决这个崩溃的原因?

我正在使用Embarcadero RAD Studio 2010(该项目主要包含C Builder代码和少量的Delphi.)

编辑:我以为我应该添加实际造成的.有一个线程叫做ReadDirectoryChangesW,然后使用GetoverlappedResult等待一个事件继续,并做一些改变.为了在设置状态标志后终止线程,也发出了事件.问题是当线程退出它从来没有称为CancelIO.结果,Windows仍然在跟踪更改,并且可能在目录更改时仍然写入缓冲区,即使缓冲区,重叠的结构和事件不再存在(也没有线程上下文被创建.)当调用CancelIO时,没有更多的崩溃.

解决方法

即使IDE提供的堆栈跟踪不是很完整,这并不意味着堆栈上仍然没有有用的信息.打开cpu视图并查看堆栈窗格;对于每个CALL操作码,返回地址被推送到堆栈上.由于堆栈向下增长,您将在当前堆栈位置上方找到这些返回地址,即在堆栈窗格中向上滚动.

主线程的堆栈将位于大约$00120000或$00180000(地址空间随机化在Vista和以上使它更随机).主要可执行程序的代码将在$40000000左右.您可以通过右键单击堆栈条目并选择“跟随 – >”来推测性地调查堆栈中不像整数数据(低值)或堆栈地址($00120000范围)的元素.近代码,这将导致反汇编窗口跳转到该代码地址.如果看起来像无效代码,它可能不是堆栈跟踪中的有效条目.如果它是有效的代码,它可能是操作系统代码(通常大约在$77000000及以上),在这种情况下,您将不会有有意义的符号,但是您经常会遇到一个实际的正确的堆栈条目.

这种技术虽然有点费力,但是当调试器无法跟踪事情时,可以获得有意义的堆栈跟踪信息.但是,如果ESP(堆栈指针)已经被拧紧,它不会帮助您.幸运的是,这很罕见.

相关文章

 从网上看到《Delphi API HOOK完全说明》这篇文章,基本上都...
  从网上看到《Delphi API HOOK完全说明》这篇文章,基本上...
ffmpeg 是一套强大的开源的多媒体库 一般都是用 c/c+&#x...
32位CPU所含有的寄存器有:4个数据寄存器(EAX、EBX、ECX和ED...
1 mov dst, src dst是目的操作数,src是源操作数,指令实现的...