分段故障处理程序中的分段错误

时间:2018-06-08 02:59:21

标签: c linux debugging linux-kernel operating-system

我遇到了在分段错误处理程序中引发分段错误的问题。虽然我已经解决了实际问题,但我仍然感到困惑,为什么以下程序不会进入无限循环:

#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一些人评论说它应该进入无限循环,但这不是当前的行为。有人可以向我解释发生了什么吗?

1 个答案:

答案 0 :(得分:4)

您在信号处理程序中发出信号。 POSIX standard says

  

[安全功能表]

     

上表中未包含的所有功能都被认为对信号不安全。在存在信号的情况下,由IEEE Std 1003.1-2001卷定义的所有功能在信号捕获功能调用或中断时应按照定义运行,但有一个例外:当信号中断不安全功能时信号捕获函数调用不安全函数,行为未定义。

void C()是一个不安全的函数,因为它不在安全函数列表中,因此让它引发信号会导致未定义的行为。 (我认为它也意味着从信号处理函数中提升信号也会导致UB,尽管措辞不清楚。)

作为未定义的行为,您不能依赖于无限循环或任何其他此类行为。

其他要点:

  • 取消引用null是未定义的行为,并且不保证首先生成SIGSEGV。
  • 在信号处理程序中调用printf是未定义的行为,因为它不是表中的安全函数之一。
  • SIGSEGV的信号处理程序返回也是UB。退出信号处理程序的唯一可移植方法是使用exit之类的调用中止该过程。