为什么有些机器有堆栈溢出,而另一些机器有分段错误?

Why stack overflow on some machines, but segmentation fault on another?

本文关键字:机器 分段 错误 堆栈 栈溢出 为什么      更新时间:2023-10-16

只是出于好奇,我正在尝试生成堆栈溢出。这段代码根据OP生成堆栈溢出,但是当我在我的机器上运行它时,它生成了一个分段错误:

#include <iostream>
using namespace std;
int num = 11;
unsigned long long int number = 22;
int  Divisor()
{
    int result;
    result = number%num;
    if (result == 0 && num < 21)
    {
        num+1;
        Divisor();
        if (num == 20 && result == 0)
        {
            return number;
        }
    }
    else if (result != 0)
    {
        number++;
        Divisor();
    }
}
int main ()
{
    Divisor();
    cout << endl << endl;
    system ("PAUSE");
    return 0;
}

同样,根据这篇文章,一些例子也应该做同样的事情。为什么我得到分割错误?

为什么我得到分段错误?

您所看到的分段错误是堆栈溢出的副作用原因为堆栈溢出,结果为段错误。

来自维基百科关于"堆栈溢出"的文章(强调我的)

…当程序试图使用比调用堆栈可用空间更多的空间时(即,当它试图访问超出调用堆栈边界的内存时,这实际上是缓冲区溢出),堆栈被称为溢出,通常会导致程序崩溃。

堆栈溢出会导致以下错误:

  • 进程SIGSEGV(分段违反)信号。
  • SIGILL(非法指令)信号。
  • SIGBUS访问无效地址。

更多信息,请阅读程序错误信号。由于行为是未定义的,上述任何一种情况都可能出现在不同的系统/体系结构中。

你本质上是在问:什么是未定义行为的行为?

答案是:未定义行为是未定义的行为。任何事情都有可能发生。

研究为什么在某个系统上出现某种未定义的行为通常是毫无意义的练习。

未定义、未指定和实现定义的行为

在堆栈溢出的情况下,程序可能会覆盖RAM中的其他变量,或者破坏正在运行的函数自己的返回地址,或者试图修改超出其给定地址范围的内存等等。根据系统的不同,您可能会遇到硬件异常和各种错误信号,例如SIGSEGV(在POSIX系统上),或者突然的程序崩溃,或者"程序似乎工作正常",或者其他什么。

其他的答案都是正确的。

然而,如果你的问题的目的是理解为什么你没有看到一个打印错误,说明堆栈溢出已经发生,答案是一些运行时库显式检测和报告堆栈溢出,而其他的没有,只是崩溃与段错误。

特别是,看起来至少一些版本的Windows检测stackoverflow并将其转换为异常,因为文档建议您可以处理它们

堆栈溢出是原因,分段错误是结果。

在linux和其他类似unix的系统上,段错误可能是堆栈溢出的结果。您不会得到程序遇到堆栈溢出的任何具体信息。

在你链接的第一篇文章中,这个人正在Windows上运行代码,这可能会有不同的行为,例如检测堆栈溢出。

我猜你使用的编译器没有启用堆栈检查

堆栈检查是一种相当简单的机制,一旦堆栈指针越过堆栈边界,它就会终止声明堆栈溢出发生的程序。通常出于优化的目的而禁用它,因为无论如何,程序几乎肯定会在堆栈溢出时崩溃。

为什么是段故障?如果没有启用堆栈检查,您的程序在用完堆栈后不会停止,而是继续进入不相关的(通常是受保护的)内存,并试图将其修改为用作新函数调用的另一个堆栈帧。疯狂随之而来,段错误发生了。