簡體   English   中英

為什么我的信號處理程序在這里沒有被多次調用?

[英]Why is my signal handler not invoked more than once here?

jmp_buf functjmp;

void sigsegv_handler(int sig) {
  sio_printf("Caught sigsegv!\n");
  siglongjmp(functjmp, 2);
  return;
}

void foo(unsigned val) {
  assert(0);
  sio_printf("entered!\n");
}

int main() {
  struct sigaction action;

  action.sa_handler = sigsegv_handler;
  sigemptyset(&action.sa_mask); /* Block sigs of type being handled */
  sigaddset(&action.sa_mask, SIGSEGV);
  action.sa_flags = SA_RESTART; /* Restart syscalls if possible */

  if (sigaction(SIGSEGV, &action, NULL) < 0) {
    sio_fprintf(stderr, "handler error!\n");
  }
  sigset_t prev_mask;
  sigprocmask(SIG_BLOCK, NULL, &prev_mask);
  if (sigsetjmp(functjmp, 0) == 0) {
    foo(*(unsigned *)0x8);
  } {
    sigprocmask(SIG_BLOCK, &prev_mask, NULL);
    sio_printf("jump handled!\n");
    foo(*(unsigned *)0x8);
  }
  sio_fprintf(stderr, "how did it come here?!\n");
}

我一直在使用 gdb 調試這段代碼,我無法弄清楚為什么程序不會用我自己的處理程序處理第二個 SIGSEGV 信號,假設程序沒有接收或發送其他信號? 任何帶有 sio 前綴的函數都是 stdio 對應函數的異步安全變體。 目前,我推測這與我在從信號處理程序返回的概念中缺少的東西有關,而 longjmp 根本不這樣做。

簡短回答:通常無法在 C 程序的 SIGSEGV 后恢復。 您可能會獲得更多的 C++ 里程。

長答案:請參閱在違反分段后恢復生機中的討論

假設可以冒未定義行為的風險:

可以重新啟用 SEGV。 核心問題是在信號處理期間,代碼顯式地阻止 SEGV 信號被觸發(使用 sigaddset)。 此外,(信號處理程序的)默認行為是在信號處理期間,相同的信號處理將被推遲,直到信號處理程序返回。 在 OP 代碼中,信號處理程序永遠不會返回(因為 siglongjmp)

這兩個問題都可以通過更改原始代碼來解決。

  // Make sure all attributes are NULL.
  struct sigaction action = {} ;

  action.sa_handler = sigsegv_handler;
  sigemptyset(&action.sa_mask); /* Block sigs of type being handled */
  // Not Needed:: sigaddset(&action.sa_mask, SIGSEGV);
  // Add SA_NODEFER to disable the deferred processing of SIGSEGV.
  action.sa_flags = SA_RESTART | SA_NODEFER ; /* Restart syscalls if possible */

  // rest of code here
  if (sigaction(SIGSEGV, &action, NULL) < 0) {
    sio_fprintf(stderr, "handler error!\n");
  }
  ...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM