为什么这行代码会导致计算机崩溃

Why does this line of code cause a computer to crash?

本文关键字:计算机 崩溃 代码 为什么      更新时间:2023-10-16

为什么这行代码会导致计算机崩溃?在特定于内存的级别会发生什么?

for(int *p=0; ;*(p++)=0)
    ;

我已经在 Everything2 上找到了"答案",但我想要一个具体的技术答案。

此代码只是将整数指针正式设置为 null,然后将它指向的整数写入 0 并递增指针,永远循环。

空指针不指向任何东西,因此向其写入 0 是未定义的行为(即标准没有说明应该发生什么(。此外,您不允许在数组外部使用指针算术,因此即使只是增量也是未定义的行为。

未定义的行为意味着编译器和库作者根本不需要关心这些情况,并且系统仍然是有效的 C/C++ 实现。如果程序员做了任何被归类为未定义行为的事情,那么无论发生什么,他/她都不能责怪编译器和库作者。进入未定义行为领域的程序员不能期待错误消息或崩溃,但如果得到一个(即使是后来执行了一百万条指令(,也不能抱怨。

在空指针表示为零并且不支持内存保护的系统上,效果或这样的循环可能是开始擦除所有可寻址内存,直到内存的某些重要部分(如中断表(损坏或直到代码在代码本身上写入零,自毁。在其他具有内存保护的系统上(当今最常见的桌面系统(,执行可能只是在第一次写入操作时停止。

> 毫无疑问,问题的原因是p没有被分配一个合理的地址。

如果在写入指针指向的位置之前没有正确初始化指针,它可能会做坏™。

它可能只是段错误,或者它可以覆盖一些重要的东西,比如函数的返回地址,在函数尝试返回之前不会发生段错误。


在 1980 年代,与我一起工作的一位理论家为 8086 编写了一个程序,每秒一次,在随机计算的地址上写入一个单词的随机数据。 计算机是一个过程控制器,具有看门狗保护和各种类型的输出。 问题是:系统在停止有效运行之前要运行多长时间? 答案是几个小时! 这生动地证明了大部分内存很少被访问。

可能会导致操作系统崩溃,或者它可能会做任何其他事情。 您正在调用未定义的行为。您不拥有地址 0 的内存,也不拥有该地址过去的内存。 你只是在蹂躏不属于你的记忆。

它的工作原理是覆盖所有地址的所有内存,从 0 开始向上。最终它会覆盖一些重要的东西。

在任何现代系统上,这只会使您的程序崩溃,而不是整个计算机。自 1985 年左右以来设计的 CPU 具有称为虚拟内存的功能,它允许操作系统重定向程序的内存地址。大多数地址根本不定向到任何地方,这意味着尝试访问它们只会使您的程序崩溃 - 而定向到某个地方的地址将被定向到分配给程序的内存,因此您只能通过弄乱它们来崩溃自己的程序。

在更旧的系统上(记住,早于1985年!(,没有这样的保护,这个循环可以访问分配给其他程序和操作系统的内存地址。

循环不是

解释问题所在的必要条件。我们只能简单地看一下第一次迭代。

int *p = 0; // Declare a null pointer
*p = 0;     // Write to null pointer, causing UB

第二行导致未定义的行为,因为这就是写入空指针时发生的情况。