C句柄信号SIGFPE并继续执行

时间:2016-09-11 00:49:19

标签: c signals

我正在尝试处理SIGFPE信号,但我的程序只是崩溃或永远运行。我必须使用signal()而不是sigaction()等其他人。

所以在我的代码中我有:

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

void handler(int signum)
{
    // Do stuff here then return to execution below
}

int main()
{
    signal(SIGFPE, handler);

    int i, j;
    for(i = 0; i < 10; i++) 
    {
        // Call signal handler for SIGFPE
        j = i / 0;
    }

    printf("After for loop");

    return 0;
}

基本上,我想在每次除0时进入处理程序。它应该在handler()函数内做任何需要的事情,然后继续循环的下一次迭代。

这也适用于需要处理的其他信号。任何帮助,将不胜感激。

2 个答案:

答案 0 :(得分:4)

如果你必须使用信号来处理FPE或你直接通过调用引起它的CPU废话而导致的任何其他信号,那么只定义当你从信号处理程序退出程序或使用longjmp获取时会发生什么进行。

还要注意恢复函数的确切位置,在计算分支的末尾但在句柄分支的开头。

不幸的是,你根本不能使用这样的signal();第二次调用导致代码崩溃。如果您打算多次处理信号,则必须使用sigaction。

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

jmp_buf fpe;

void handler(int signum)
{
    // Do stuff here then return to execution below
    longjmp(fpe, 1);
}

int main()
{
    volatile int i, j;
    for(i = 0; i < 10; i++) 
    {
        // Call signal handler for SIGFPE
        struct sigaction act;
        struct sigaction oldact;
        memset(&act, 0, sizeof(act));
        act.sa_handler = handler;
        act.sa_flags = SA_NODEFER | SA_NOMASK;
        sigaction(SIGFPE, &act, &oldact);

        if (0 == setjmp(fpe))
        {
            j = i / 0;
            sigaction(SIGFPE, &oldact, &act);
        } else {
            sigaction(SIGFPE, &oldact, &act);
            /* handle SIGFPE */
        }
    }

    printf("After for loop");

    return 0;
}

答案 1 :(得分:2)

警告:很抱歉在游行中下雨,但你真的不想这样做。

捕获[{1}}等[外部生成的]信号是完全有效的,可以正常清理和终止可能打开部分文件的程序。

然而,内部生成的信号,例如SIGINT, SIGTERM, SIGHUP SIGILL, SIGBUS, SIGSEGV很难从有意义地恢复 。前三个是错误 - 纯粹而简单。而且,IMO,SIGFPE也是一个错误。

发出此类信号后,您的程序处于不安全不确定状态。即使捕获信号并执行SIGFPE也无法解决此问题。

并且,没有办法确切地说出伤害有多严重。或者,如果程序试图继续,成为的伤害有多严重。

如果你得到longjmp/siglongjmp,那是否为浮点计算[你可能能够平滑]。或者,它是否为整数除零?正在进行什么计算?而且,在哪里?你不知道。

尝试继续有时会造成10倍的伤害,因为现在程序失控了。恢复后,程序可能没问题,但可能不会。因此,事件发生后程序的可靠性可以确定。

导致SIGFPE的事件(即)计算是什么?也许,它只是一个单独的鸿沟,而是导致价值为零的计算链。这些价值观去了哪里?在恢复操作发生后,代码是否会使用这些现在可疑的值?

例如,程序可能会覆盖错误的文件,因为失败的计算在某种程度上涉及选择调用者将要使用的文件描述符。

或者,你泄漏了内存。或者,破坏堆。或者,堆分配代码本身是错误吗?

考虑以下功能:

SIGFPE

即使信号处理程序执行void myfunc(char *file) { int fd; fd = open(file,O_WRONLY); while (1) { // do stuff ... // write to the file write(fd,buf,len); // do more stuff ... // generate SIGFPE ... x = y / z; } close(fd); } siglongjmp写入的文件现在也已损坏/截断。并且,文件描述符不会被关闭。

或者,如果myfunc从文件中读取数据并将数据保存到某个数组,该怎么办?该数组仅部分填充。现在,你得到myfunc。这被SIGFPE的信号处理程序拦截。

siglongjmp的其中一位来电者会myfunc到&#34;赶上&#34;这个。但是,它能做什么?来电者没有知道有多糟糕的事情。它可能假设读取的缓冲区sigsetjmp已完全形成并将其写入不同的文件。那个其他文件现在已经损坏了。

<强>更新

糟糕,忘了提及未定义的行为 ......

通常,我们将UB(例如写入数组末尾)与段错误[myfunc]相关联。但是,如果它导致SIGSEGV呢?

它不仅仅是一个错误的计算&#34; - 我们在最早的检测点捕获[并忽略] UB。如果我们进行恢复,下一次使用可能会更糟。

以下是一个例子:

SIGFPE