【问题标题】:How to debug a traceless crash如何调试无痕崩溃
【发布时间】:2011-07-06 08:18:57
【问题描述】:

在开发应用程序的过程中,我们特别遇到了一个非常讨厌的错误。症状很简单,就是进程消失了。日志只是突然结束,没有崩溃转储或任何东西可以找到,不存在僵尸进程。 Dr.Watson 没有发现任何东西让我们无影无踪。

该错误重现起来并不简单,重现此错误平均需要 3-4 小时,重复执行相同的操作。因此,某处存在某种竞争条件。我们有处理 SEH 和正常异常的特殊函数,所以这些都不应被忽视。

调试必须在特殊的计算机上进行,因为它运行在非常专业的硬件上。所以只有远程调试可用。并且当连接远程调试时,C++ builder 不会注意到应用程序丢失,当我们尝试对不存在的进程进行任何调试时会崩溃和烧毁。

我们在这款软件中使用了多种技术:

  • OpenGL
  • Directshow + 一些 COTS 过滤器
  • COM/DCOM
  • 串行 COM 端口与专用硬件通信
  • C++ Builder(使用与 VC++ 不同的堆栈帧)

所以,如您所知,我在这里没有太多工作要做。我现在正在做的是,我试图通过登录代码中的不同位置来缩小范围,以查找代码中是否有某个特定点发生错误。我还试图删除我正在执行的操作的尽可能多的方面,以使案例尽可能简单。但这是一个非常复杂的操作,这个过程需要很多时间,而且时间(像往常一样)是一种稀缺资源。

我想知道是否有人对我有好的提示,无论是原因(通常是什么导致进程在没有任何通知的情况下停止)或调试这种难以捉摸的失败的技术?

【问题讨论】:

  • 我在此将此类虫子命名为“百慕大三角虫”。
  • 您在哪个版本的 Windows 上运行它?
  • 这是在定制的 Embedded XP 上运行的。
  • @caf hehe,我实际上将这个错误命名为 Ninja bug,因为它会杀死进程并消失得无影无踪:D

标签: c++ c windows debugging c++builder


【解决方案1】:

如果您希望能够更频繁地调试场景,请尝试在虚拟机中运行它,并在它发生之前每隔一段时间拍摄一次“快照”。

这里的问题可能是与您提到的通过串行端口连接的专用硬件的状态不一致。

【讨论】:

  • 首先,硬件使得虚拟化环境几乎(没有双关语)变得不可能。其次,我无法理解硬件的状态如何影响我们的流程。它只能通过串口访问。所以内部的错误可能会导致固件挂起,通信问题,但进程终止???
【解决方案2】:

你为什么不试试windbg,它也可以通过命名管道或串口远程连接。


没有 BSOD,没有 Rootkit,没有乐趣 ~~ Biswanth Chowdhury - Win32 内核*

【讨论】:

  • 我猜windbg 会遇到不熟悉的堆栈帧的问题,但如果它给我的地址比我现在拥有的更多。我去看看。
  • 谷歌搜索windbg Borland 显示您可以获取函数名但不能获取变量名。
  • @MSalters,谢谢,我不知道。我之前尝试过其他 vc++ sentric 工具,但没有得到太多信息,但知道这一点我一定会尝试的。
  • 在你认为执行语句改变程序逻辑的地方尝试在windbg中使用断点。
  • @Biswanath Chowdhury :不,我没有说,我也不打算说 VC++ 调试器。我完全意识到与 WinDBG 的区别,两者都并行安装在我的机器上。 VC++ 调试器对 C++ 的理解要好得多,但 WinDBG 对 x86 的理解要好得多。
【解决方案3】:

当 Windows 下的本机代码遇到堆栈溢出(通常是由于无限递归)时,进程有时会完全按照您的描述消失。标准错误对话框和异常处理需要一些堆栈空间,如果没有堆栈空间,它们就无法运行。 (更高版本的 Windows 可以更好地处理此问题,应该总是引发异常 - Windows XP 在此定义下不是“更高版本”。)

最简单的暴力调试方法是在每个函数的入口(可能还有出口)写入日志消息。这些消息必须直接进入文件,如果你有缓冲输出(例如cout 或类似的)你应该每次都立即刷新它。当您设法导致崩溃时,您将获得至少可以定位问题的堆栈跟踪。


无限递归并不是堆栈溢出的唯一原因(尽管它是更常见的原因)。如果在堆栈上分配了非常大的变量(通常是具有数千/数百万个元素的数组),则可能会出现相同的问题。特别是alloca()“函数”可以伪装这种堆栈溢出的原因。

如果您在调试器下运行并中断/登录保护页面异常,您将在堆栈扩展时收到通知 - 让异常得到处理,因为它用于提交更多内存并且实际上可能与问题。


进程消失的最终非堆栈溢出原因是对exit()ExitProcess() 的杂散调用。全文搜索应该能够在很大程度上排除这种情况 - 调试器中 ExitProcess 函数上的断点将完全做到这一点。

【讨论】:

  • +1 用于提及编写您自己的跟踪日志。在尝试调试一些晦涩的东西时,每一点日志信息都像黄金一样!
  • 您可能是对的,但我们已经设置了结构化异常处理 (SEH),如果发生堆栈溢出,操作系统应该通知它。同样在较早的情况下,我看到堆栈溢出,它们通常会使 dr.watson 做出反应并弹出进程已被终止的通知。 cout 调试就是我现在正在做的。希望它会产生一些结果。
  • @daramarak 这取决于系统。我刚刚编写了一个简短的测试应用程序(在汇编中,start: push 0 jmp start),它在 Win7 x64 上引发了STATUS_STACK_OVERFLOW,但在 WinXP x86 上消失了。您可以尝试的另一件事是减少堆栈限制(应该在链接器选项中)并查看错误是否会更快发生。
  • +1,好的,我会进一步调查。将尝试重新创建堆栈溢出以查看这是否真的未被检测到。
【解决方案4】:

尝试使用较小的堆运行它。如果问题是由于您的内存不足造成的,这将导致崩溃更快发生。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-30
    • 2017-02-22
    • 1970-01-01
    • 2019-08-26
    相关资源
    最近更新 更多