首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C处理信号SIGFPE并继续执行

C处理信号SIGFPE并继续执行
EN

Stack Overflow用户
提问于 2016-09-11 00:49:18
回答 2查看 7.6K关注 0票数 5

我试图处理一个SIGFPE信号,但我的程序只是崩溃或永远运行。我必须使用signal(),而不是像sigaction()这样的其他。

所以在我的代码中:

代码语言:javascript
复制
#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()函数中做它需要做的任何事情,然后继续循环的下一次迭代。

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

EN

回答 2

Stack Overflow用户

发布于 2016-09-11 01:01:18

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

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

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

代码语言:javascript
复制
#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;
}
票数 5
EN

Stack Overflow用户

发布于 2016-09-11 03:37:12

警告:抱歉下雨了,但你真的不想这样做。

捕获外部生成的信号(如SIGINT, SIGTERM, SIGHUP等)是完全有效的,以允许优雅地清理和终止可能打开部分写入的文件的程序。

然而,内部生成的信号,如SIGILL, SIGBUS, SIGSEGVSIGFPE,很难有意义地恢复。前三个是bugs-纯而简单。而且,国际海事组织,SIGFPE也是一个很难对付的错误。

在发出这样的信号后,您的程序处于不安全和不确定状态。即使是捕获信号和执行longjmp/siglongjmp也不能解决这个问题。

而且,没有办法确切地知道损害有多严重。或者,如果计划继续下去,损害会有多严重。

如果您得到SIGFPE,它是否用于浮点计算,您可能能够平滑处理。还是整数除以零?正在做什么计算?还有,在哪?你不知道。

试图继续有时会造成10倍的损害,因为现在程序已失去控制。在恢复之后,程序可能是可以的,但可能不是。因此,程序在事件发生后的可靠性,不能以任何程度的确定性来确定。

什么是事件(即)导致SIGFPE的计算?也许,这不仅仅是一个除法,而是导致数值为零的计算链。这些值到哪里去了?这些值现在是否会在恢复操作发生后被代码使用?

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

或者你漏了记忆。或者,破坏这堆东西。还是堆分配代码本身中的错误?

考虑以下职能:

代码语言:javascript
复制
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的调用者之一执行sigsetjmp来“捕获”这个。但是,它能做什么呢?打电话的人不知道事情有多糟。它可能假定myfunc正在读取的缓冲区已经完全形成,并将其写入另一个文件。另一个文件现在已损坏。

更新:

哦,忘了提到未定义的行为..。

通常,我们将UB与分段故障SIGSEGV相关联,例如在数组结束后写入UB。但是,如果它反而导致了SIGFPE呢?

这不再仅仅是一种“错误的计算”--我们在最早的检测点捕捉并忽略了UB。如果我们进行恢复,下一次的使用可能会更糟。

下面是一个例子:

代码语言:javascript
复制
// assume these are ordered in memory as if they were part of the same struct:
int x[10];
int y;
int z;

void
myfunc(void)
{

    // initialize
    y = 23;
    z = 37;

    // do stuff ...

    // generate UB -- we run one past the end of x and zero out y
    for (int i = 0;  i <= 10;  ++i)
        x[i] = 0;

    // do more stuff ...

    // generate SIGFPE ...
    z /= y;

    // do stuff ...

    // do something _really_ bad with y that causes a segfault or _worse_
    // sends a space rocket off-course ...
}
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39431879

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档