2014-03-24 92 views
0

我想從我的代碼處理SIGSEGV信號。我在Fedora 15下的C語言中編寫了下面的代碼。我的問題是信號處理程序沒有被調用來處理第二個分段錯誤。任何人都可以指出我做錯了什麼。無法處理連續的SIGSEGV信號

typedef struct _ST_DEMO 
{ 
    int m_iUnused; 

    _ST_DEMO() 
    { 
     m_iUnused = 0; 
    } 
} ST_DEMO; 

jmp_buf ex_buf__; 

static void sig_hdl (int sig, siginfo_t *siginfo, void *context) 
{ 
    cout<<"Inside Signal Handler."<<endl; 
    longjmp(ex_buf__, 1); 
} 

int main (int argc, char *argv[]) 
{ 
    ST_DEMO* pStDemo = 0; 
    struct sigaction act; 

    memset (&act, '\0', sizeof(act)); 

    /* Use the sa_sigaction field because the handles has two additional parameters */ 
    act.sa_sigaction = &sig_hdl; 

    /* The SA_SIGINFO flag tells sigaction() to use the sa_sigaction field, not sa_handler. */ 
    act.sa_flags = SA_SIGINFO; 

    if (sigaction(SIGSEGV, &act, NULL) < 0) 
    { 
     perror ("sigaction"); 
     return 1; 
    } 

    if(!setjmp(ex_buf__)) 
    { 
     cout<<"Before First Seg Fault."<<endl; 
     cout<<pStDemo->m_iUnused<<endl; 
    } 
    else 
    { 
     cout<<"After jump."<<endl; 
    } 

    cout<<"Before Second Seg Fault."<<endl; 
    cout<<pStDemo->m_iUnused<<endl; 

    while(1) 
    { 
     sleep(1); 
    } 

    return 0; 
} 

回答

2

longjmp會使你跳轉到的位置,但你不會從信號處理程序返回。這意味着信號仍然被阻塞(這是信號的默認行爲,在信號處理程序返回之前它們會被屏蔽)。

您可以通過在longjmp之前清除處理程序中的信號掩碼來指示您希望信號再次出現來解決此問題。

  • act.sa_flags中使用SA_NODEFER標誌來防止它首先被屏蔽。
  • 使用siglongjmp/sigsetjmp功能,這之前或之後longjmp的節省面膜爲你

或者

  • 調用sigprocmask自己揭露它。

警告:這是一個非常危險的事情(抓住SIGSEGV,然後longjmp退出信號處理程序),幾乎不可能做任何有用的事情。

如果內存訪問錯誤發生在任何不是異步信號安全且可重入的函數中,無論如何您都無法以任何一種理智的方式繼續。

但是由於網站上有很多類似的問題,我猜這是一些練習。

相關問題: Catching Segmentation Violations and Getting on with Life

也有用

Longjmp out of signal handler? longjmp() from signal handler

+0

非常感謝您的回覆。 SA_NODEFER標誌起作用。順便說一下,這不是一個練習。我正在使用第三方庫從我的軟件訪問數據庫。如果數據庫以某種方式脫機,該庫崩潰。我只是試圖處理SIGSEGV信號來阻止我的代碼被核心轉儲。但根據你的建議,即使處理完信號後,我仍然無法做任何理智的事情,那麼我必須想到別的東西。再次感謝。 – Souvik

+0

啊,是的,從sigsegv恢復是非常非常困難的。對於這類問題,我通常會創建一個輔助進程來處理實際的數據庫流量,並使用IPC進行通信。如果這是極端的矯枉過正,取決於你。 :) – perh