SIGSEGV处理程序中的Segfault
让我们假设我有以下C代码:
static void handler(int sig, siginfo_t *si, void *unused) { printf("BOOM!\n"); //another segfault here exit(-1); } int main(int argc, char *argv[]) { struct sigaction sa; sa.sa_flags = SA_SIGINFO; sigemptyset(&sa.sa_mask); sa.sa_sigaction = handler; if (sigaction(SIGSEGV, &sa, NULL) == -1) perror("failed to set handler"); // call other stuff here, somewhere in the callstack a segfault happens }
如果执行遇到第一个分段错误,则将触发处理程序。 但是,当处理程序本身由于某种原因发生分段错误时会发生什么? 它是否会使用新的siginfo_t
再次调用处理程序,还是会立即终止程序?
如果再次调用处理程序会像这样工作:
int in_handler = 0; static void handler(int sig, siginfo_t *si, void *unused) { printf("BOOM!\n"); if(!in_handler) { in_handler = 1; //code that could possibly segfault } else { //totally safe code } exit(-1); }
我之所以要问的是我目前正在用C编写某种unit testing框架。如果测试用例由于某些非法的内存访问而失败,我想将所有剩余的测试标记为失败。 如果由于某种原因,测试已经严重搞砸了堆,这个操作可能会失败,因为我必须遍历数据结构并将该信息写入xml文件。 但是如果将所有剩余的测试标记为失败,我仍然希望保留测试失败的测试信息。
从sigaction(2)
的手册页sigaction(2)
:
#include
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); ....
sigaction
结构被定义为类似的东西struct sigaction { void (*sa_handler)(int); void (*sa_sigaction)(int, siginfo_t *, void *); sigset_t sa_mask; int sa_flags; void (*sa_restorer)(void); }
….
sa_mask
给出了一个信号掩码,在执行信号处理程序时应该阻塞这些信号。 此外,除非使用SA_NODEFER
标志,否则将阻止触发处理程序的信号。
因为在设置信号处理程序时没有设置SA_NODEFER
标志,所以如果在仍处于信号处理程序中时发生另一个段错误,则不会再次调用它。 退出后,之前被阻止的信号将被传送。
如果SIGSEGV出现在SIGSEGV处理程序中,至少Linux将使用SIGSEGV的默认信号处理程序,请参阅kernel / signal.c ,这样就不会再次调用处理程序。 引用的代码似乎只在内核尝试为信号处理程序设置堆栈帧时发生段错误时使用(例如,因为堆栈指针无效)。
当您的segfault处理程序段错误时,您的程序将处于非常破碎的状态,我不会依赖任何东西并使用一些处理该情况的包装器。
除此之外,要符合POSIX标准,您不能在信号处理程序中使用printf或类似的东西。 对于您可以使用的function,请检查man 7 signal
(寻找安全function)。 write()
在该列表上,因此您可以使用它编写自己的输出函数。