我知道您可以通过使用编译器标志和信号处理来处理整数溢出(请参阅this question的已接受答案)。
实际上,你实际上可以prevent it。
但是我一直无法找到有关如何处理/避免堆栈溢出的任何信息:
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
}
我发现的两个解决方案是:“不使用递归”和“编译器优化可以消除尾递归,因此问题得以解决”。但我正在寻找一个不同的解决方案。
编辑:我喜欢避免它的方式(see accepted answer)。
避免解决方案:
假设你有函数的大小(例如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);
}
现在,我或许可以获得function size with nm -S和硬编码(我知道接受的答案说它无法完成)。附加说明:我几乎可以肯定通过调用sizeof(tryToBreak)或sizeof(& tryToBreak)无法获得此值。
另外,我可以设置stack size并获得堆栈上可用空间的粗略近似值。
在我开始研究该解决方案之前(也许看到它失败了),我想知道是否有另一种方法(可能更简单,更精确)。
编辑:现在我找到了避免它的方法,真正的问题是:你如何恢复 来自使用信号处理的堆栈溢出。
处理解决方案:
当进程收到“分段错误”信号并且必须handle it时,我不确定该怎么办。第一:你怎么知道它是由堆栈溢出引起的?第二:你从堆栈溢出中恢复什么?
答案 0 :(得分:2)
虽然很难以完全便携的方式进行,但可以定义自己的堆栈。原则上,您可以使用posix线程(请参阅pthread_set_stackaddr
),因此它甚至不是特别奇特。
然后您可以使用mprotect
在堆栈末尾创建一个红色区域(“警戒区域”)。堆栈溢出将导致SIGSEGV
,您可以处理;将为sigaction处理程序提供保护错误的地址,因此您可以检入处理程序以查看它是否是您的一个红色区域的一部分。 (当然,您必须使用备用堆栈运行信号处理程序。请参阅SA_ONSTACK
标志和sigaltstack
。
从堆栈溢出中恢复(没有编译器帮助)比较棘手。
顺便说一句,函数的大小(作为由一系列机器指令组成的可重定位目标文件)与函数堆栈框架的大小之间没有关系。所以nm
对你没有任何好处。