调试在不同位置崩溃10次的程序

您将获得在运行时崩溃的应用程序的源代码。 在调试器中运行10次后,您发现它永远不会在同一个地方崩溃。 该应用程序是单线程的,仅使用C标准库。 哪些编程错误可能导致此崩溃? 你会如何测试每一个?

您的代码可能在C标准中调用具有未定义行为的任​​何内容,包括(但不限于):

  1. 不初始化变量但尝试使用其值。
  2. 取消引用空指针。
  3. 读取或写入数组的末尾。
  4. 定义以下划线和大写字母或另一个下划线开头的预处理器宏。

列表很长,但C规范中的附件J.2提供了未定义行为的简明列表。

  • 磁盘已满,即其他进程可能会删除不同的文件,从而导致可用空间增加
  • 代码取决于计时器
  • 内存问题,即其他进程分配和/或释放内存
  • 指针指向内存中的随机位置,该位置由另一个进程更改,导致某些值“有效”(尽管非常罕见)

通常情况下,可能存在其他过程的情况。 请注意,您说只有您的程序是单线程的,其他程序可以并行运行。

容易:无限循环。 只有在调用堆栈溢出时才会崩溃,这可能发生在任何地方,具体取决于调用堆栈可用的内存量。

如果您认为存在单个错误且应用程序在不同位置崩溃,则可能是悬空指针。 访问已经释放的内存将为您提供垃圾值(在大多数情况下可能是段错误),它们将在应用程序创建和破坏变量并执行内存操作时看似随机覆盖。 这可能就像丢失的malloc一样简单或者free太多。

但是,如果第一次尝试没有揭示问题的根源,我根本不打扰调试应用程序。 如果一个应用程序在十个不同的地方崩溃,当应用程序使用看似无关的数据时,作者肯定已经编写了大量的代码而没有在过程中编译和测试它,现在很无奈,因为一个错误导致另一个错误。 我会礼貌地要求应用程序的程序员与自己进行性交,并在完成后,从头开始重写错误的代码,编译和测试每几行。

他们正在寻找的答案是使用未初始化的变量,并且取决于它是否为默认值。 例如:

 int a; // default value 0 int b[10]; int main() { for (;a++;a<10) { b[a] = 0; } } 

调试时不会崩溃,因为您调试未经优化的代码,因此将应用默认值。 开始时为0. Gcc -O3或-Os没有任何问题,但是不会初始化该值,使​​其成为随机值,非常不可能为0,并且b [a]将增加地址(在“平均值”中)案例“,警告适用”直到数据段之外,导致SIGSEGV。

但是会有关于此的编译器警告。

您可以依靠链接属性使这个问题更难。 (查看“static int c”在全局范围内的作用)。