10

我是Linux信号的新手,请帮忙。以下代码在 Linux 2.6 gcc 中运行时获取核心转储。

$ ./a.out
浮点异常(核心转储)

问题:
1. 既然安装了进程信号掩码,那么第40行生成的“SIGFGE”不应该volatile int z = x/y;被屏蔽吗?
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;
    }
4

2 回答 2

4

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

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

(来自sigprocmask规范

于 2011-07-08T18:46:55.457 回答
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}
于 2019-07-04T16:59:25.780 回答