【问题标题】:Recursion segmentation fault and StackGuard递归分段错误和 StackGuard
【发布时间】:2017-03-14 22:28:54
【问题描述】:

假设我有一个函数,它所做的只是调用自身而没有任何终止。

myFunction(){
    myFunction()
}

如果我运行一个包含这个函数的程序,我最终会得到一个分段错误。为什么会这样?堆栈空间不足?

另外,StackGuard 能否防止此故障?为什么或为什么不?

【问题讨论】:

  • 如果您尝试运行该代码,应该会因为语法错误而导致它甚至无法构建。
  • 这个递归没有停止条件。你会期待什么?
  • 堆栈是有限的资源。在 Windows 上,进程的默认堆栈大小是单个 MB。防止它的唯一方法是有一个实际终止递归的终止条件。
  • @EugeneSh。好吧,我对无限递归的期望是堆栈溢出。
  • @Timmy 是的,但是函数调用不会覆盖金丝雀,它只是在堆栈上创建一个新的框架,其中包含一组新的金丝雀。事实上,使用堆栈金丝雀会使堆栈溢出更快,因为堆栈帧的空间更少。

标签: c recursion segmentation-fault stack-overflow


【解决方案1】:

每次调用函数时,都会在内存中为该函数调用创建一个新的堆栈帧。当函数返回时,该堆栈消失。由于您的函数不会返回并继续调用新调用,因此它将继续创建堆栈帧,这意味着最终您将耗尽内存来保留这些堆栈帧。

【讨论】:

    【解决方案2】:

    由于递归是无限的,并且对于每次调用,返回地址和基指针(帧指针)至少被压入堆栈,你最终将耗尽堆栈空间,或者更一般地,耗尽内存,如内存是一种有限的资源。

    没有什么可以防止这种情况,因为是程序员“设计”了这种无限递归。您期望“防止此故障”是什么?正如我所说,这不是错误,因为它是程序的设计。您只是用完了有限的资源,导致操作系统中止程序。


    编辑:以下是截取段错误的示例(未经测试,基于 VC2008 doc):
    jmp_buf home;
    
    void myFunction(void)
    {
        myFunction();
    }
    void SegvHandler(int signal)
    {
        longjmp(home);
    }
    int main(void)
    {
        signal(SIGSEGV, SegvHandler);
        if (setjmp(home)) {
            printf("Oops...\n)
            return 1;
        }
        myFunction();
        return 0;
    }
    


    测试:在 VC2008 中测试后,似乎无法捕获此错误。原因似乎是/可能是:首先发生堆栈溢出,现在没有更多的堆栈空间来调用另一个函数,信号处理程序。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-05
      • 2018-03-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-01-14
      相关资源
      最近更新 更多