c - 为什么我的信号处理程序在这里没有被调用多次?

标签 c unix signals

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++ 可能会取得更多进展。

长答案:请参阅 Coming back to life after Segmentation Violation 中的讨论

假设可以承担未定义行为的风险:

可以重新启用 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");
  }
  ...

关于c - 为什么我的信号处理程序在这里没有被调用多次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59596577/

相关文章:

在 X 中创建隐藏的、不可见的窗口?

Swift,在 GCD 中,SIGUSR1 不起作用

c++ - 充满 QLineEdits 的 QTableWidget 不会触发信号

c++ - C 中的 undefined reference 错误

c - C中的BST遍历

c - 函数中的段错误

c - 需要帮助从 c 文件中提取注释

bash - 使用值提取所需的列

c - 在 c 中使用信号并从程序中的特定点恢复

c - 为什么要阻止文件作为控制终端打开(使用 O_NOCTTY)?