2011-04-26 61 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