如何将SIGFPE转换为C ++ - 异常

时间:2016-07-06 10:12:27

标签: c++ linux exception signals

在Win32下,使用_set_se_translator很容易将SEH异常转换为C ++异常。是否有类似的方法将某些信号转换为C ++ - Linux上的例外?我需要将SIGFPE映射到C ++ - 异常。

2 个答案:

答案 0 :(得分:2)

使用g ++,您可以使用-fnon-call-exceptions选项,只是从FPE信号处理程序中抛出异常。请注意,并非每个信号都可以像这样映射,只有信号来自陷阱指令。幸运的是,SIGFPE就是这样一个信号。

答案 1 :(得分:1)

您无法在Linux等POSIX系统上可靠。有关详细信息,另请参阅this。请注意,在您的情况下,您无法使用signalfd(2)。我假设您在x86-64或其他常用架构上使用Linux。

仔细阅读signal(7)(特别是关于信号处理程序中 async-signal-safe 函数的说法,它们是处理SIGFLE等信号的唯一方法)。另请阅读C ++ 11标准或C99标准关于signal的内容。大多数C ++实现有时可能会为运行时支持函数生成一些隐式调用,这些函数不是 async-signal-safe (特别是那些抛出异常的函数。所以你不能可靠地抛出来自信号处理程序的异常。)

在实践中,以下将是错误的信号处理程序

/// WRONG CODE, against signal(7) since calling 
/// non-async-signal-safe functions from the C++ runtime
void badSIGFPEhandler(int sig) {
  if (sig == SIGFPE)
    throw std::runtime_error("got SIGFPE");
}    

您可以通过编译g++ -Wall -O -fverbose-asm -S(然后查看发出的.s汇编程序文件)进行检查,它正在调用一些非异步信号安全函数(来自C ++运行时),如{ {1}},__cxa_allocate_exception__cxa_throw 禁止 signal(7) ....

实际上,从_Unwind_Resumeabort的信号处理程序中唯一安全的做法是设置一些_exit标志,或使用少数 async-signal-safe 功能,例如write(2)上的pipe(7)内容。另外,从信号处理程序中抛出异常并不比从它调用volatile sigatomic_t更糟糕(许多人错误地这样做);它是被禁止的,但它经常可以工作。我仍然不建议这样做,特别是在长时间运行的程序中,或者不经常发生崩溃的情况下。

详细了解undefined behavior,特别是Lattner关于What every C programmer should know about undefined behavior的博客。

实际上,处理信号的唯一可靠且可移植的方法是使用信号处理程序,只设置一些printf标志。但是如果你为volatile sigatomic_t执行此操作,则您的实现很可能会在相同的状态下重新启动相同的计算,因此在SIGFPE处理时无限循环。另请参阅this关于-fnon-call-exceptions(因此我认为n.m.'s answer可能并不总是正确且可靠;事实上它似乎是未定义的行为,通常似乎有用。)

PS。实际上,我强烈怀疑Windows进行转换的方式不符合C ++ 11或C ++ 14标准(或C99或C11标准),并且您可以使用C ++(或C99或C11)的标准符合实现Windows不允许做你的建议;可能Clang或GCC就是这样的实现。