我遇到了在分段错误处理程序中引发分段错误的问题。虽然我已经解决了实际问题,但我仍然感到困惑,为什么以下程序不会进入无限循环:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void C()
{
int *p = NULL;
*p = 3;
}
void B()
{
C();
}
void segfault_sigaction(int signal, siginfo_t *si, void *arg)
{
printf("Came in sigaction.\n");
//if(si)
//printf("Caught segfault at address %p\n", si->si_addr);
B();
}
int main(void)
{
struct sigaction sa;
memset(&sa, 0, sizeof(struct sigaction));
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = segfault_sigaction;
sa.sa_flags = SA_SIGINFO;
sigaction(SIGSEGV, &sa, NULL);
segfault_sigaction(0, NULL, NULL);
return 0;
}
以上代码的输出如下:
Came in sigaction.
Came in sigaction.
Segmentation fault (core dumped)
在这篇类似帖子的评论中:Segmentation fault within segmentation fault handler一些人评论说它应该进入无限循环,但这不是当前的行为。有人可以向我解释发生了什么吗?
答案 0 :(得分:4)
您在信号处理程序中发出信号。 POSIX standard says:
[安全功能表]
上表中未包含的所有功能都被认为对信号不安全。在存在信号的情况下,由IEEE Std 1003.1-2001卷定义的所有功能在信号捕获功能调用或中断时应按照定义运行,但有一个例外:当信号中断不安全功能时信号捕获函数调用不安全函数,行为未定义。
void C()
是一个不安全的函数,因为它不在安全函数列表中,因此让它引发信号会导致未定义的行为。 (我认为它也意味着从信号处理函数中提升信号也会导致UB,尽管措辞不清楚。)
作为未定义的行为,您不能依赖于无限循环或任何其他此类行为。
其他要点:
printf
是未定义的行为,因为它不是表中的安全函数之一。SIGSEGV
的信号处理程序返回也是UB。退出信号处理程序的唯一可移植方法是使用exit
之类的调用中止该过程。