为什么某些事情永远不会随着调试器而崩溃?

时间:2010-08-01 22:58:00

标签: c++ c debugging visual-c++

我的应用程序使用GLUTesselator来检查复杂的凹多边形。它在我运行普通版本exe时随机崩溃,但如果我在VS中开始调试它永远不会崩溃。我在这里找到了这个基本上是我的问题:

The multi-thread debug CRT (/MTd) masks the problem, because, like
     

Windows对生成的进程执行操作   一个调试器,它提供给你的   编程调试堆,即   初始化为0xCD模式。   可能在某处您使用了一些   未初始化的记忆区域   堆作为指针,你解除引用   它;你得到两个调试堆   出于某种原因离开它(也​​许吧   因为在地址0xbaadf00d和   0xcdcdcdcd有效分配   内存),但与“正常”堆   (通常初始化为0)你   获得访问冲突,因为你   取消引用NULL指针。

问题是在GLU32.dll中发生崩溃,我无法找出为什么它有时试图取消引用空指针。当我的多边形变得相当大并且有很多点时,它似乎会这样做。我该怎么办?

由于

3 个答案:

答案 0 :(得分:3)

生活中的一个事实是,有时程序在调试器中的行为有所不同。在你的情况下,一些内存的初始化方式不同,它的布局也可能不同。并发程序中的另一个常见情况是时序不同,并且在调试器中经常发生竞争条件。

您可以尝试手动将堆初始化为其他值(或查看Visual Studio中是否有此选项)。通常初始化为非零会捕获更多错误,但在您的情况下可能不是这种情况。您还可以尝试使用程序的内存映射来安排页面0xcdcdc000未映射。

Visual Studio可以在访问特定内存地址时设置断点,您可以尝试这一点(它可能会使程序的速度明显慢于变量断点)。

答案 1 :(得分:2)

  

但如果我在VS中开始调试,它永远不会崩溃。

好吧,我不确定为什么,但是在Visual Studio程序中调试有时可以通过访问某些内存区域而无需调试器就会崩溃。我不知道确切的原因,但有时0xcdcdcdcd和0xbaadfood与此无关。它只是访问某些地址不会导致问题。当发生这种情况时,您需要找到猜测问题的替代方法。

  

我该怎么办?

可能的解决方案:

  1. 在程序中安装异常处理程序(_set_se_translator,如果我没记错的话)。在访问冲突时,请尝试MinidumpWriteDump。稍后使用Visual Studio进行调试(afaik,崩溃转储调试在快递版中是n / a),或使用windbg。
  2. 使用即时调试程序。视觉工作室的非快递版本具有此功能。可能有其他选择。
  3. 编写自定义内存管理器(它将覆盖new / delete并提供malloc / free替代品(如果使用它们)),它将占用大块内存,用VirtualProtect锁定所有未使用的内存。在这种情况下,即使在调试模式下,所有无效访问都将导致崩溃。这样的内存管理器需要大量内存,因为要锁定,每个块应该与页面对齐。
  4. 为所有可疑的函数调用添加过多的日志记录。将大量文本/调试信息转储到文件(或stderr)中 - 参数值,数组,您怀疑可能与崩溃相关的所有内容,每次写入文件后刷新,否则在崩溃期间会丢失一些信息。通过这种方式,您将能够猜出程序崩溃之前发生了什么。
  5. 尝试调试发布版本。如果在项目设置中为发布版本启用“调试信息”,则应该能够在某种程度上执行此操作。
  6. 尝试在项目属性(configuration properties->c/c++->code genration)中打开/关闭“基本运行时检查”和“缓冲区安全检查”。
  7. 尝试找一些外部工具 - 像valgrind或bounds checker。虽然,对我来说,#3比这种方法更可靠。虽然这真的取决于问题。

答案 2 :(得分:2)

指向早期问题和两个想法的链接。

首先,您可能希望查看以前question关于Windows的valgrind替代品。有很多关于可以帮助你的程序的好提示。

现在的想法:

1)调试器可能会阻止您的程序在您正在测试的代码中崩溃,但它并没有解决问题。在最糟糕的情况下,你只是在街上踢罐头,但仍然存在腐败现象,但从你的运行方式来看并不明显。当您发货时,您可以放心,有人会再次遇到问题。

2)在这种情况下经常发生的事情是错误不在问题发生的地方附近。虽然您可能会注意到GLU32.dll中的问题,但可能更早出现了损坏,甚至可能在不同的线程或函数中,这不会导致问题,并且在稍后的某个时刻程序回到损坏的区域并失败。