gdb“程序正常退出”当它不应该

Posted

技术标签:

【中文标题】gdb“程序正常退出”当它不应该【英文标题】:gdb "Program exited normally" when it shouldn't 【发布时间】:2011-12-09 23:17:03 【问题描述】:

我正在使用 gcc44 和 gdb 在 64 位 Linux CentOS 5.7 服务器上调试一些 ANSI C 代码。

在我的一个函数的中间,我有一个循环 192 次的 for 循环(循环中有 2 行代码)。如果我在 for 循环开始时设置 gdb 并设置断点,我可以单步执行 for 循环 192 次,然后它会退出 for 循环并在 for 循环之后继续执行下一行代码。这都是使用“s”或“n”逐步执行 gdb 中的代码。一切正常。

现在,我不再使用“s”或“n”单步执行 for 循环以到达 for 循环之后的下一行代码,而是启动 gdb,然后在该行结束后的行设置断点for 循环。如果我然后在 gdb 中按“c”,它会给我“程序正常退出”。我希望 gdb 在 for 循环之后的代码行上的这个断点处停止。 (!?)

作为另一个实验,我了解到 gdb 确实成功地停止在任何行上设置的任何断点之后紧跟 for 循环之后的代码行。

从诸如此类的问题来看,也许其他人有过这种经历(其中还有 2 个额外的参考资料):

gdb error "Program exited normally"

它在 gdb 中是可重复的。在没有深入研究相关代码的情况下,任何人之前都看到过这种行为和/或知道我可以检查什么?

编辑 1

如果我在断点行包含printf("\n"); 会导致上述问题,将该行上的内容移动到此 printf 代码下方的一行,则一切正常(例如 gdb 在 printf 行上停止)。

我什至可以在之前有问题的代码行上成功设置断点,现在是 printf 行之后的下一行。奇怪!

【问题讨论】:

线程问题?使用调试器单步执行将很好地隐藏竞争条件。 W/O 最少的代码或回溯 (bt),任何人都很难为您提供帮助。 如果是竞争条件阻止 gdb 正常运行,那么是否也会阻止程序正常运行(不使用 gdb 时)?如果是这样,我什至不会意识到它正在发生,如果不是因为这次奇怪的事故——人们如何解决这种情况? 一种解决方法是使用 'u'ntil 命令退出循环。 我不熟悉...它是如何工作的?是 gdb 命令吗? 你编译过优化了吗? 【参考方案1】:

你的编译器在欺骗你。

嗯,不是真的,但它并没有完全按照你的怀疑做。

编译器的第一个原则概念是将 C 的每一行按顺序转换为一条或多条汇编指令,并按照与 C 代码相同的顺序执行汇编。

实际上,编译器会重新组织事物以优化速度或空间。如果一条指令被认为对程序状态没有净影响,它可以被完全删除。因此,当您告诉 GDB 在那一行中断时,嗯.. 没有带有调试信息的汇编指令指向 C 的那一行。

【讨论】:

感谢 gravitron。参考上面文章中的最后一句话,GDB 可以停在有问题的代码行上,具体取决于它在代码中的位置。如果在 for 循环和这行有问题的代码之间插入了新的(虚拟)代码,那么 GDB 会突然开始看到这个有问题的代码。也许这是乔上面建议的比赛条件?不确定。 我怀疑这是一种竞争条件。更有可能的是,有问题的行在没有 printf 的情况下是不相关的,并且可能与 printf 相关(编译器无法判断)。例如,如果将值传递给 printf,编译器将不再优化冗余调用,因为它不知道 printf 是否修改了它。

以上是关于gdb“程序正常退出”当它不应该的主要内容,如果未能解决你的问题,请参考以下文章

当它到达第四个标签时,它不应该去第一个

Sympy解决返回奇怪的字典,当它不应该返回任何

R:一列中值的平均值,当它不应该等于 0 时

当它不应该用Java时,它会变成180

Postgresql 查找每个类型的最大 transaction_id 给出重复项(当它不应该用于 PK 时)

sys模块