浮点异常核心转储

10

我是 Linux 信号的新手,请帮忙。

当在 Linux 2.6 gcc 上运行以下代码时会出现核心转储:

$ ./a.out
Floating point exception (core dumped)

问题如下:
1. 由于进程信号掩码已安装,volatile int z = x/y; 的第40行生成的 "SIGFPGE" 是否应该被阻止?
2. 如果没有被阻止,由于已安装信号处理程序, "SIGFPE" 应该被信号处理程序捕获,而不是导致核心转储吗?
3. 如果我注释掉第40行的volatile int z = x/y;,并使用第42行的 raise(SIGFPE);,则一切都按照我的预期工作。在这里,x/0 和 raise SIGFPE 之间有什么区别?

以下是代码:

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

    void sig_handler(int signum)
    {
       printf("sig_handler() received signal %d\n", signum);
    }


    int main(int argc, char * argv[])
    {

       // setup signal mask, block all signals
       sigset_t set;
       sigfillset(&set);

       if(sigprocmask(SIG_BLOCK, &set, NULL)<0)
       {
          perror("failed to set sigmask");
          return -1;
       }

       // install signal handler for SIGFPE
       struct sigaction act;
       act.sa_handler = sig_handler;
       act.sa_mask = set;
       act.sa_flags = 0;
       if(sigaction( SIGFPE, &act, NULL)<0)
       {
          perror("sigaction failed");
          exit(-1);
       }

       volatile int x =1;
       volatile int y =0;
       volatile int z = x/y; //line 40

       //raise(SIGFPE); //line 42

       printf("point 1000\n");

       return 0;
    }
2个回答

4

当信号被阻塞时,任何由硬件陷阱引起的SIGFPE都会导致未定义行为:

如果在这些信号(SIGFPE、SIGILL、SIGSEGV或SIGBUS)被阻塞时生成了任何一个信号,则结果是未定义的,除非该信号是由kill()函数、sigqueue()函数或raise()函数生成的。

(摘自sigprocmask规范


尽管最新的规范是Issue 7。 :-) - Nemo
@Nemo:谢谢。规则仍然存在,但措辞略有变化,因此我更新了我的答案。 - Ben Voigt
1
感谢您的回答。我讨厌“未定义”。 - John Crane

0

man signal

根据 POSIX 的规定,在忽略了非由 kill(2) 或 raise(3) 产生的 SIGFPE、SIGILL 或 SIGSEGV 信号后,进程的行为是未定义的。整数除以零的结果是未定义的。

在某些架构上,它将生成一个 SIGFPE 信号。(同时,将最负整数除以-1可能会产生 SIGFPE)。忽略这个信号可能会导致无限循环。

我之前尝试解决为什么除以零会导致正/负无穷大的问题时发现了这一点:IEEE 754,除以零

这是你永远不想到达的地方:

void divZeroHdlr(int sig) {
  printf("div by zero: %d\n",sig)
  exit(1);}

int main(int argc, char *argv[]) {
  signal(SIGFPE, divZeroHdlr)
  int n = 1/0}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接