在C语言中处理/避免堆栈溢出

3
我知道你可以使用编译器标志和信号处理来处理整数溢出(请参见此问题的已接受答案)。实际上,你实际上可以预防它。 但是,我无法找到任何关于如何处理/避免堆栈溢出的信息:
void breakStack(int num){
     // Implied check to see if addition will cause integer overflow
     int tmp = num + 1;
     // Code to see if next call will cause a stack
     // overflow and avoid it
     breakStack(tmp);
}

或者:

void breakStack(int num){
    // Implied check to see if addition will cause integer overflow
    int tmp = num + 1;
    breakStack(tmp);
}

void stackOverFlowHandler(int signum){
    // Code to handle stack overflow
}
我找到的两个解决方法是:“不使用递归”和“编译器优化可以消除尾递归,因此问题得以解决”。但我正在寻找另一种解决方案。

编辑:我发现了一种避免它的方法(见已接受的答案)。

避免解决方案:
假设您有函数的大小(例如50字节)和堆栈上剩余的空闲空间量(例如200字节),那么:

void tryToBreakStack(int num){
    // Implied check to see if addition will cause integer overflow
    int tmp = num + 1;
    if(functionSize>leftSpace){
        return;
    }
    tryToBreakStack(tmp);
}

现在,我可能能够使用 nm -S 函数获取函数大小并进行硬编码(我知道被接受的答案说这是不可能的)。另外需要注意的是:我几乎可以确定不能通过调用 sizeof(tryToBreak) 或 sizeof(&tryToBreak) 来获得此值。
此外,我可能能够设置堆栈大小并大致估算堆栈上的空闲空间。

在我开始尝试这种解决方案之前(也许会失败),我想知道是否有其他方法可以做到这一点(也许更容易和更精确)。

编辑:既然我找到了避免它的方法,那么真正的问题是:如何使用信号处理从堆栈溢出中恢复。

处理方案:
当进程收到“分段错误”信号并且必须处理它时,我不确定该怎么做。首先:如何知道这是由堆栈溢出引起的?其次:如何从堆栈溢出中恢复?


如果你想避免 Stack Overflow,就不应该在 Stack Overflow 上发布问题 :p - hanshenrik
1个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
2

虽然在完全可移植的情况下很难做到,但您可以定义自己的堆栈。原则上,您可以使用posix线程(请参见pthread_set_stackaddr)来实现,因此这甚至不是特别奇异的。

然后,您可以使用mprotect在堆栈末尾创建一个红色区域(“保护区”)。堆栈溢出将导致SIGSEGV,您可以处理它。sigaction处理程序将提供保护故障的地址,因此您可以在处理程序中检查它是否属于您的其中一个红色区域。(当然,您必须使用备用堆栈运行信号处理程序。请参见SA_ONSTACK标志和sigaltstack

没有编译器帮助的情况下从堆栈溢出中恢复更加棘手。

顺便说一句,函数的大小(作为由一系列机器指令组成的可重定位对象)与函数的堆栈帧的大小之间没有关系。因此,nm真的对您没有任何好处。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,