2011-04-26 82 views

回答

15

这是一个最小的示例程序,它使用sigaltstack来捕捉无限递归。如果您注释掉sigaltstack调用或SA_ONSTACK标志,则信号处理程序将无法运行,因为它没有剩余堆栈并且程序只会崩溃。

#define _XOPEN_SOURCE 700 
#include <signal.h> 
#include <unistd.h> 
void handler(int sig) 
{ 
    write(2, "stack overflow\n", 15); 
    _exit(1); 
} 
unsigned infinite_recursion(unsigned x) { 
    return infinite_recursion(x)+1; 
} 
int main() 
{ 
    static char stack[SIGSTKSZ]; 
    stack_t ss = { 
     .ss_size = SIGSTKSZ, 
     .ss_sp = stack, 
    }; 
    struct sigaction sa = { 
     .sa_handler = handler, 
     .sa_flags = SA_ONSTACK 
    }; 
    sigaltstack(&ss, 0); 
    sigfillset(&sa.sa_mask); 
    sigaction(SIGSEGV, &sa, 0); 
    infinite_recursion(0); 
} 

一个更复杂的使用可能会实际执行siglongjmp跳出信号处理和回哪里可避免无限递归的一个点。如果正在使用异步信号不安全的库调用,或者数据可能处于不安全/不可恢复的状态,但是如果您正在执行纯算术计算,则这可能无效。

对于信号处理程序来说,更好的任务可能是对任何尚未保存到磁盘的有价值/关键数据进行紧急转储。如果你不能调用异步信号不安全的函数,这可能很困难,但是如果你付出一些努力,通常是可能的。

+0

这段代码不工作....它给了我一个分裂故障 – 2013-01-24 19:18:48

+2

它适用于我(修复一个错字之后)。顺便说一下,启用优化后,gcc会为该函数生成一个无限循环而不是递归,因此不会溢出堆栈。用'-O0',信号处理程序按预期运行。 – 2013-01-25 02:38:08

+0

我按照你所说的尝试过-O0,但它仍然给我一个分裂故障。它可以是gcc版本吗? – 2013-01-28 15:08:56