在C中捕获堆栈溢出的最佳方法是什么?
进一步来说:
AC程序包含脚本语言的解释器.
脚本不受信任,可能包含无限的递归错误.口译员必须能够抓住这些并顺利地继续下去.(显然,这可以通过使用软件堆栈来部分处理,但是如果可以用C语言编写大量的库代码块,性能会大大提高;至少,这需要在脚本创建的递归数据结构上运行C函数.)
捕获堆栈溢出的首选形式将涉及longjmp返回主循环.(丢弃在主循环下面的堆栈帧中保存的所有数据是完全可以的.)
回退可移植解决方案是使用局部变量的地址来监视当前堆栈深度,并使用每个递归函数来包含对使用此方法的堆栈检查函数的调用.当然,这会在正常情况下产生一些运行时开销; 这也意味着如果我忘记将堆栈检查调用放在一个地方,解释器将有一个潜在的错误.
有没有更好的方法呢?具体来说,我不期待更好的可移植解决方案,但如果我有一个针对Linux的系统特定解决方案和另一个适用于Windows的解决方案,那就没关系.
我见过在Windows上引用了一些称为结构化异常处理的东西,尽管我看过的引用一直是将它转换为C++异常处理机制; 可以从C访问它,如果是这样,它对这种情况有用吗?
我了解Linux可以捕获分段故障信号; 是否可以将其可靠地转换为longjmp回到主循环?
Java似乎支持在所有平台上捕获堆栈溢出异常; 它是如何实现的?
在我的脑海中,捕捉堆栈过度增长的一种方法是检查堆栈帧地址的相对差异:
#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则写入一条消息。
当然,这假设您所在的架构使用线性始终向下增长或始终向上增长堆栈。
您不必在每个函数中都进行此检查,但通常会在达到您选择的限制之前捕获过大的堆栈增长。