预先在运行时检测堆栈溢出

J. *_*son 12 c recursion stack overflow detection

我有一个相当大的递归函数(我也用C编写),虽然我毫不怀疑堆栈溢出发生的情况极不可能,但它仍然是可能的.我想知道你是否可以检测堆栈是否会在几次迭代中溢出,这样你就可以在不崩溃程序的情况下进行紧急停止.

fuz*_*fuz 9

在C编程语言本身,这是不可能的.一般情况下,在用完之前,您无法轻易知道堆积不足.我建议您在实现中对递归深度设置一个可配置的硬限制,这样您就可以在超出深度时简单地中止.您还可以重写算法以使用辅助数据结构而不是通过递归使用堆栈,这为您提供了更大的灵活性来检测内存不足的情况; malloc()告诉你什么时候失败.

但是,您可以在类UNIX系统上使用类似的过程获得类似的东西:

  1. 使用setrlimit设置软堆栈限制低于硬堆栈限制
  2. 为两者建立信号处理程序SIGSEGVSIGBUS获得堆栈溢出的通知.有些操作系统可以SIGSEGV为其他操作系统生成SIGBUS.
  3. 如果您收到这样的信号并确定它来自堆栈溢出,请提高软堆栈限制setrlimit并设置一个全局变量以识别出现这种情况.创建变量,volatile以便优化器不会破坏平原.
  4. 在您的代码中,在每个递归步骤中,检查是否已设置此变量.如果是,则中止.

这可能无处不在,并且需要特定于平台的代码才能发现信号来自堆栈溢出.并非所有系统(特别是早期的68000系统)在获得SIGSEGV或之后都能继续正常处理SIGBUS.

Bourne shell使用类似的方法进行内存分配.


mai*_*ual 4

这是一个适用于 win-32 的简单解决方案。实际上类似于 Wossname 已经发布的内容,但没那么恶心:)

unsigned int get_stack_address( void )
{
    unsigned int r = 0;
    __asm mov dword ptr [r], esp;
    return r;
}
void rec( int x, const unsigned int begin_address )
{
    // here just put 100 000 bytes of memory
    if ( begin_address - get_stack_address() > 100000 )
    {
        //std::cout << "Recursion level " << x << " stack too high" << std::endl;
        return;
    }
    rec( x + 1, begin_address );
}
int main( void )
{
    int x = 0;
    rec(x,get_stack_address());
}
Run Code Online (Sandbox Code Playgroud)

  • 啊,内联汇编给人一种温暖、模糊、工作安全感:D 很好。 (12认同)