不使用调试器时出现段错误(segfault)

77

我有一个多线程的C程序,在程序的特定点始终会发生分段错误。当我使用gdb调试运行时,没有显示错误。你能想到为什么只有在不使用调试器时才会发生这种错误吗?不能使用调试器找到问题真是太烦人了!


7
这种类型的软件漏洞被称为“Heisenbug”(海森堡Bug),可能有很多原因。 - Sven Marnach
这个错误是否与窗口管理和/或User32.dll有关? - user541686
1
我遇到了这样的问题,我的程序只在使用GDB时崩溃。问题是一个未初始化的类成员变量在运行程序时仍然得到值0,但是当我在GDB中运行它时,它具有一些巨大的值,将其用作数组索引时会导致segfault。 - GWW
不涉及Windows - 我正在使用Linux 2.6.32-24-generic#43-Ubuntu。 - Benubird
12
你尝试过生成一个核心转储文件吗?在程序运行之前,在调试器以外运行命令 ulimit -c unlimited,然后在程序发生错误退出时使用 gdb myprogram core 命令。这样,gdb 就能够对你的段错误进行死后调试了。 - Robie Basak
程序在那个特定点发生了什么?你试图解引用一个指针吗?调用另一个函数?是什么呢? - John Bode
5个回答

112

经典的Heisenbug。来自维基百科:

时间也可以是Heisenbugs的一个因素。在调试器的控制下执行程序可能会改变程序的执行时间与正常执行相比。当程序被单步源行在调试器中减速时,例如存在竞态条件等时间敏感的错误可能无法再现。特别是当行为涉及与调试器不受控制的实体的交互时,例如调试两台计算机之间的网络数据包处理且只有一台计算机处于调试器控制之下。

调试器可能会改变时间,并隐藏竞态条件。

在Linux上,GDB还会禁用地址空间随机化,而您的崩溃可能与地址空间布局有关。尝试(gdb) set disable-randomization off

最后,ulimit -c unlimited和事后调试(Robie已经建议)可能有效。


12
“set disable-randomization off” 对我来说解决了一个类似的问题! - Marcus Johansson

9
也许当使用时,内存映射在您的溢出/下限上没有践踏导致崩溃的内存位置。或者可能是不再触发的竞争条件。尽管听起来不直观,但你应该为你的程序能够崩溃而感到高兴

一些建议

  1. 尝试静态代码分析器,例如免费的cppcheck
  2. 尝试malloc()调试器,如libefence
  3. 尝试通过valgrind运行它

5

通过调试它,您正在更改其运行环境。听起来您正在处理某种竞争条件,并且通过调试它,事物被略微不同地安排,因此您不会遇到该问题。或者,事物以稍微不同的方式存储,因此不会发生这种情况。您能否在代码中添加一些调试输出以帮助解决问题?那可能会对其影响较小,并允许您找到问题。


2

我之前也遇到过这个问题!这是一种竞争条件,当我用调试器逐步执行代码时,我所在的线程速度足够慢,无法触发竞争条件。非常糟糕。


1
如果您使用的是gcc,请尝试使用-Wall选项获取所有警告。如果您使用像Eclipse这样的IDE,则会自动执行此操作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接