捕获堆栈溢出

rwa*_*ace 14 c stack-overflow

在C中捕获堆栈溢出的最佳方法是什么?

进一步来说:

AC程序包含脚本语言的解释器.

脚本不受信任,可能包含无限的递归错误.口译员必须能够抓住这些并顺利地继续下去.(显然,这可以通过使用软件堆栈来部分处理,但是如果可以用C语言编写大量的库代码块,性能会大大提高;至少,这需要在脚本创建的递归数据结构上运行C函数.)

捕获堆栈溢出的首选形式将涉及longjmp返回主循环.(丢弃在主循环下面的堆栈帧中保存的所有数据是完全可以的.)

回退可移植解决方案是使用局部变量的地址来监视当前堆栈深度,并使用每个递归函数来包含对使用此方法的堆栈检查函数的调用.当然,这会在正常情况下产生一些运行时开销; 这也意味着如果我忘记将堆栈检查调用放在一个地方,解释器将有一个潜在的错误.

有没有更好的方法呢?具体来说,我不期待更好的可移植解决方案,但如果我有一个针对Linux的系统特定解决方案和另一个适用于Windows的解决方案,那就没关系.

我见过在Windows上引用了一些称为结构化异常处理的东西,尽管我看过的引用一直是将它转换为C++异常处理机制; 可以从C访问它,如果是这样,它对这种情况有用吗?

我了解Linux可以捕获分段故障信号; 是否可以将其可靠地转换为longjmp回到主循环?

Java似乎支持在所有平台上捕获堆栈溢出异常; 它是如何实现的?

Dav*_*ble 4

在我的脑海中,捕捉堆栈过度增长的一种方法是检查堆栈帧地址的相对差异:

#define MAX_ROOM    (64*1024*1024UL)    // 64 MB

static char *   first_stack = NULL;

void foo(...args...)
{
    char    stack;

    // Compare addresses of stack frames
    if (first_stack == NULL)
        first_stack = &stack;
    if (first_stack > &stack  &&  first_stack - &stack > MAX_ROOM  ||
        &stack > first_stack  &&  &stack - first_stack > MAX_ROOM)
        printf("Stack is larger than %lu\n", (unsigned long)MAX_ROOM);

    ...code that recursively calls foo()...
}
Run Code Online (Sandbox Code Playgroud)

这会将第一个堆栈帧的地址与foo()当前堆栈帧地址进行比较,如果差值超过,MAX_ROOM则写入一条消息。

当然,这假设您所在的架构使用线性始终向下增长或始终向上增长堆栈。

您不必在每个函数中都进行此检查,但通常会在达到您选择的限制之前捕获过大的堆栈增长。

  • 次要:“(64*1024*1024UL)”-->“(64UL*1024*1024)”。以最宽的类型开头,否则 `64*1024` 是 0,16 位 `unsigned`。在嵌入式产品中很常见,SO 是一个令人担忧的问题 - 尽管这种设备是否具有 64 MB 内存值得怀疑。 (2认同)