SIGSEGV不能两次被抓获

时间:2018-08-09 10:51:12

标签: c signals sigsegv setjmp

以下代码在第二个printf处有分段错误,而预期会被处理(setjmp)。请注意,由于格式字符串错误,每个printf都会产生分段错误。第一个分段错误得到了正确处理,但第二次错误没有得到正确处理(注释掉printf之后运行代码不会造成段错误)。

#include <stdio.h>
#include <setjmp.h>
#include <signal.h>

static jmp_buf escapeCallJmpBuf;
static void sigsegv_handler(int signal, siginfo_t *info, void *context) {
  longjmp(escapeCallJmpBuf, 1);
}

int main(int argc, char **argv) {
  struct sigaction segvAction, segvActionOld;
  segvAction.sa_handler = 0;
  memset(&segvAction.sa_mask, 0, sizeof(segvAction.sa_mask));
  segvAction.sa_flags = SA_SIGINFO;
  segvAction.sa_sigaction = sigsegv_handler;
  sigaction(SIGSEGV, &segvAction, &segvActionOld);

  int res;

  // Catch first segmentation fault
  if (setjmp(escapeCallJmpBuf)) {
    res = 1;
  } else {
    printf ("%s\n", 2); // This will segfault
    res = 0;
  }

  // try to catch second segmentation fault
  if (setjmp(escapeCallJmpBuf)) {
    res = 2;
  } else {
    printf ("%s\n", 3); // This will segfault
    res = 0;
  }

  sigaction(SIGSEGV, &segvActionOld, 0);
  return res;
}

1 个答案:

答案 0 :(得分:1)

setjmplongjmp不一定恢复信号掩码(取决于实现方式)。可能发生的情况是在处理完第一个SIGSEGV之后,信号掩码恢复为默认值。因此第二个SIGSEGV未被捕获,即,默认操作代替您的默认操作发生,该操作将退出该过程。

您应该改用sigsetjmpsiglongjmp

POSIX状态:

  

不确定longjmp()是恢复信号掩码,保持信号掩码不变还是将其恢复为调用setjmp()时的值。

并建议:

  

其行为取决于信号掩码值的应用程序   不应使用longjmp()和setjmp(),因为它们对   信号掩码未指定,但应使用siglongjmp()   和sigsetjmp()函数(可以保存和恢复信号掩码   在应用程序的控制之下)。

此外,从信号处理程序跳转还存在一些限制:

  

建议应用程序不要调用longjmp()或   信号处理程序中的siglongjmp()。为了避免未定义的行为,当   从信号处理程序调用这些函数,应用程序需要   确保以下两件事之一:

     

在调用longjmp()或siglongjmp()之后,该过程仅调用   异步信号安全功能,不会从初始调用返回   到main()。

     

其处理程序调用longjmp()或siglongjmp()的任何信号均被阻止   在每次对非异步信号安全函数的调用期间,都没有这样的情况   从初始调用返回到main()之后进行调用。