【问题标题】:Why i am getting continuous SIGSEGV in the below C code为什么我在下面的 C 代码中得到连续的 SIGSEGV
【发布时间】:2019-07-07 01:34:09
【问题描述】:

我正在尝试学习信号。我知道无效的内存访问会导致段错误。因此,我为 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 信号。我想我应该只收到一次信号。你们能解释一下为什么我不断收到信号吗

【问题讨论】:

标签: c linux signals


【解决方案1】:

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

this answer 中查看更多信息。

【讨论】:

  • 虽然你的观点是正确的,但这更像是一个评论而不是一个答案:-)
【解决方案2】:

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

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

有安全和不安全的处理方法

注意事项

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

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

signal() 的唯一可移植用途是将信号的处置设置为 SIG_DFL 或 SIG_IGN。使用 signal() 时的语义 建立一个信号处理程序 系统(并且 POSIX.1 明确允许这种变化);请勿将其用于此目的。

POSIX.1 通过指定 sigaction(2) 解决了可移植性的问题,当一个 调用信号处理程序;使用该接口而不是 signal()。

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

接下来,处理 SIGSEGV 是一头怪事:

How to write a signal handler to catch SIGSEGV?

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

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

如何使用信号 (2) 来做到这一点

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

您可以使用sigjmpsetsiglongjmp

sigjmpset 标记了siglongjmp 应该跳转到的点。第一次调用sigjmpset(设置点)返回0。当siglongjmp 跳转到它时,(这意味着由于长跳转而再次调用它),它返回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;
}

【讨论】:

    猜你喜欢
    • 2018-07-04
    • 2013-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多