为什么我在下面的 C 代码中得到连续的 SIGSEGV

Why i am getting continuous SIGSEGV in the below C code

我正在尝试学习信号。我知道无效的内存访问会导致段错误。因此,我为 SIGSEGV 信号注册了一个信号处理程序。

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


void sighandler(int signum)
{
    printf("%s\n", __func__);
}

int main()
{
    int *a = NULL;
    signal(SIGSEGV, sighandler);
    *a = 5;
    return 0;
}

运行 这段代码,我不断收到 SIGSEGV 信号。我以为我应该只收到一次信号。你们能解释一下为什么我不断收到信号

SEGV 处理程序完成后,触发 re-executes 的指令。由于您没有采取任何措施来防止下一次执行出错,您将再次获得 SEGV,无限次。

更多内容见this answer

信号处理程序正在返回触发它的指令,即 *a = 5 导致它循环。

您有几个问题,包括在信号处理程序中使用 printf

有安全且 not-safe 的处理方法

注意事项

通常不建议使用 signal(2) 进行信号处理。

由于信号语义的工作方式,处理 SIGSEGV 甚至更加复杂。引用手册页:

The only portable use of signal() is to set a signal's disposition to SIG_DFL or SIG_IGN. The semantics when using signal() to establish a signal handler vary across systems (and POSIX.1 explicitly permits this variation); do not use it for this purpose.

POSIX.1 solved the portability mess by specifying sigaction(2), which provides explicit control of the semantics when a signal handler is invoked; use that interface instead of signal().

所以你应该做的第一件事就是使用 sigaction.

接下来,处理 SIGSEGV 是一个奇怪的野兽:

How to write a signal handler to catch SIGSEGV?

Does linux allow any system call to be made from signal handlers?

有很好的答案并进入具体细节。那里给出的一些答案中有外部链接。

如何使用 signal(2)

嗯 :-) 假设您想要使用 signal(2) 并且您想以一种奇怪的方式玩这个 ....

您可以使用 sigjmpsetsiglongjmp

sigjmpset 标记了 siglongjmp 应该跳转到的点。第一次 sigjmpset 被调用(设置点)它 returns 0。当 siglongjmp 跳转到它时,(这意味着它由于长跳转而再次被调用),它 returns 1.

这意味着我们可以这样做:

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

sigjmp_buf env;
int sigsav;

void sighandler(int signum)
{

    const char msg[] = "Skipping signal\n";
    write(2, msg, sizeof(msg));
    siglongjmp(env, sigsav);
}

int main()
{
    int *a = NULL;

    signal(SIGSEGV, sighandler);
    if(!sigsetjmp(env, sigsav)) {
        printf("setting value of a\n");
    *a = 5;
    }
    else {
    printf("returned to sigsetjmp, but now we skip it!\n");
    }
    return 0;
}