【问题标题】:Why stack overflow on some machines, but segmentation fault on another?为什么在某些机器上堆栈溢出,但在另一台机器上出现分段错误?
【发布时间】:2015-08-01 10:17:30
【问题描述】:

出于好奇,我正在尝试生成堆栈溢出。这段代码会生成一个 Stack Overflow according to the 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;
}

另外,根据this 的帖子,那里的一些示例也应该这样做。为什么我会出现分段错误?

【问题讨论】:

    标签: c++ segmentation-fault stack-overflow


    【解决方案1】:

    堆栈溢出可能导致以下错误

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

    更多信息请阅读Program Error Signals。由于行为未定义,上述任何一种情况都可能出现在不同的系统/架构上。

    【讨论】:

      【解决方案2】:

      为什么会出现分段错误?

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

      来自wikipedia article 的“堆栈溢出”(强调我的

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

      【讨论】:

        【解决方案3】:

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

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

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

        Undefined, unspecified and implementation-defined behavior

        在堆栈溢出的情况下,程序可能会覆盖 RAM 中的其他变量,或破坏正在运行的函数自己的返回地址,或尝试修改其给定地址范围之外的内存等。根据系统,您可能会遇到硬件异常以及各种错误信号,例如 SIGSEGV(在 POSIX 系统上),或突然的程序崩溃,或“程序似乎运行良好”,或其他。

        【讨论】:

        • 只是出于好奇,你能在这里给出未定义行为的章节吗?我在标准的(非官方)副本中找不到任何提及堆栈溢出的内容(溢出似乎总是意味着数字溢出)。无限递归似乎属于一般章节“不能指望任何实现提供无限资源”,但挥舞未定义行为似乎需要更具体的东西。
        • @MarcvanLeeuwen 如果标准未涵盖行为,则它是未定义的行为。 3.4.3 未定义行为 behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements。 C 标准不需要明确地将某些东西列为未定义的行为来使其如此:如果标准根本没有提到会发生什么就足够了。例如,无限次调用递归函数会发生什么。
        • 你的论点不明确。递归不是错误的程序结构,也不涉及错误的数据。标准(我在想 C++,但在这一点上 C 是相似的)完美地描述了如何处理递归调用。我没有看到任何提及尝试函数调用可能会由于运行时堆栈上的空间不足而失败(而动态内存耗尽的可能性已明确满足,并且本身不会导致 UB);也许我看错了地方。该标准似乎指定无限重复,如循环,而不是 UB
        • @MattMcNabb 怎么样?如果这个特定的堆栈溢出导致了分段错误,这并不意味着下次您遇到分段错误时,那是因为堆栈溢出。了解导致崩溃的原因当然具有教育意义。已经知道是什么导致了它并检查了它的后果,但更少。
        • 是的。 “如果它不在标准中,我不在乎”是一种非常没有生产力的态度。现实世界是存在的。
        【解决方案4】:

        发布的其他答案都是正确的。

        但是,如果您的问题的目的是了解为什么您没有看到说明发生堆栈溢出的打印错误,则答案是某些运行时库显式检测并报告堆栈溢出,而另一些则没有,然后简单地因段错误而崩溃。

        特别是,看起来至少某些版本的 Windows 会检测到 Stackoverflow 并将其转换为异常,因为 documentation 建议您可以处理它们。

        【讨论】:

          【解决方案5】:

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

          在 linux 和其他类似 unix 的系统上,segmentation fault 可能是堆栈溢出的结果。您没有得到程序遇到堆栈溢出的任何特定信息。

          在您链接的第一篇文章中,此人正在 Windows 上运行代码,其行为可能会有所不同,例如专门检测堆栈溢出。

          【讨论】:

            【解决方案6】:

            我猜你使用的编译器没有启用stack checking

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

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

            【讨论】:

            • 通常,特意确保刚刚超过堆栈末尾的内存未被映射,这样您就不会进入例如 malloc()ed 数据结构。
            猜你喜欢
            • 1970-01-01
            • 2018-09-18
            • 2015-11-08
            • 1970-01-01
            • 2011-06-30
            • 1970-01-01
            • 2011-06-30
            • 1970-01-01
            • 2015-09-08
            相关资源
            最近更新 更多