Under Win32 it's easy to convert a SEH-exception into a C++-exception with _set_se_translator. Is there a similar way to convert certain signals into C++-exceptions on Linux? I need a mapping of SIGFPE to a C++-exception.
-
Perhaps you should **edit your question** to improve and motivate it, in particular explain why you want to do that, and what precise circumstances of `SIGFPE` you are really thinking about. – Basile Starynkevitch Jul 06 '16 at 10:34
-
@Basile Starynkevitch The motivation for this ought to be obvious to every software engineer with a minimum of experience! – Sep 24 '20 at 15:53
-
A better (and usually faster, and certainly more portable) practice is to avoid integer division by zero or (with IEEE doubles) use signaling NAN. See [this answer](https://stackoverflow.com/a/64033548/841108) to a related answer, and read [signal-safety(7)](https://www.man7.org/linux/man-pages/man7/signal-safety.7.html) after [signal(7)](https://www.man7.org/linux/man-pages/man7/signal.7.html) and of course the http://floating-point-gui.de/ – Basile Starynkevitch Sep 24 '20 at 16:58
2 Answers
With g++, you can use -fnon-call-exceptions
option and just throw an exception from the FPE signal handler. Note not every signal can be mapped like that, only signals that arise from trapping instructions. Fortunately SIGFPE is such a signal.

- 112,515
- 14
- 128
- 243
-
1Are you sure that would always work reliably (e.g. a divide by zero inside some destructor, perhaps of an exception) – Basile Starynkevitch Jul 06 '16 at 12:01
-
1@BasileStarynkevitch It will be just like throwing from a destructor. Why would you do floating point in a destructor anyway? – n. m. could be an AI Jul 06 '16 at 12:22
-
My feeling is that this way of doing gives undefined behavior which might usually work. – Basile Starynkevitch Jul 07 '16 at 04:48
-
@BasileStarynkevitch Of course it is UB accirding to the standard, but gcc defines what happens when you do it. It's an extension. – n. m. could be an AI Jul 07 '16 at 05:34
-
2The [GCC documentation](https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html) says about `-fnon-call-exceptions` "Generate code that allows trapping instructions to throw exceptions. Note that this requires platform-specific runtime support that does not exist everywhere. Moreover, it only allows trapping instructions to throw exceptions, i.e. memory references or floating-point instructions. It does not allow exceptions to be thrown from arbitrary signal handlers such as SIGALRM.". I don't understand it as you do. – Basile Starynkevitch Jul 07 '16 at 07:11
-
@BasileStarynkevitch I don't know how to understand it in any other way. – n. m. could be an AI Jul 07 '16 at 07:16
-
It does not say anything about signal handlers (which should call only async-signal-safe functions). It does not say that the code won't call them. – Basile Starynkevitch Jul 07 '16 at 07:17
-
@BasileStarynkevitch async-signal-safe is a Pisix terms and applies to Posix functions. Note Pisix specifies it is OK to jongjmp out of a signal handler unless it's nested (i.e. it interrupts another signal handler). So it would be OK to longjmp out of a SIGFPE handler if your other signal handlers don't do arithmetic that may invoke a trap. A throw is a non-local transfer just like longjmp. The signal handling machinery shouldn't care. Given that, I don't see a way to give any other interpretation to the documentation. Do you have an alternative interpretation? If so, which one? – n. m. could be an AI Jul 07 '16 at 08:22
-
@BasileStarynkevitch the identical option for the Intel C++ compiler is documented more clearly: "You must write a signal handler that catches the signal and throws a C++ exception". https://software.intel.com/en-us/node/582095 – n. m. could be an AI Jul 07 '16 at 08:44
-
Check that your `icc` compiler does not generate any call to some runtime function which is not async-signal-safe – Basile Starynkevitch Jul 07 '16 at 08:59
-
@BasileStarynkevitch Why should I? I trust the documentation. If it says it's OK to throw an exception, that's quite enough. I also trust the runtime not to kill any puppies while unwinding the stack. – n. m. could be an AI Jul 07 '16 at 09:04
-
But as I have shown, your answer is wrong with `g++` (and I'm pretty sure also with `icc`). Perhaps you have encountered a documentation bug for `icc`. Then please report it to your vendor. – Basile Starynkevitch Jul 07 '16 at 09:06
-
I don't believe you have shown anything regarding either gcc or icc. If anything, there is a gcc documentation bug. The documentation weakly implies that it is safe to throw exceptions from signal handlers, and is widely interpreted as such. It should state it directly, just like icc documentation does. – n. m. could be an AI Jul 07 '16 at 09:17
-
Please show precisely where the GCC documentation tells that it is safe to throw exceptions from signal handlers. I am an occasional GCC contributor and could submit a documentation patch. – Basile Starynkevitch Jul 07 '16 at 09:18
-
1@BasileStarynkevitch In the previous comment, I stated the documentation **implies** so without **saying** so, and that it **should** say so, which it currently doesn't. There is no way to give any other useful interpretation to the action of the switch. If the switch does nothing useful, it should be removed altogether. – n. m. could be an AI Jul 07 '16 at 09:55
You cannot do reliably that on POSIX systems such as Linux. See also this for more details. Notice that you can't use signalfd(2) in your case. I assume you are using Linux on x86-64 or some other commonly available architecture.
Read very carefully signal(7) (in particular what is said about async-signal-safe functions in signal handlers, and they are the only way to handle signals like SIGFLE
). Read also what the C++11 standard or the C99 standard say about signal
. Most C++ implementations might sometimes generate some implicit call to runtime support functions which are not async-signal-safe (in particular, those for throwing an exception. So you cannot reliably throw an exception from a signal handler).
In practice, the following would be a wrong signal handler:
/// 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");
}
You can check by compiling it with g++ -Wall -O -fverbose-asm -S
(then looking into the emitted .s
assembler file) that it is calling some non-async-signal-safe functions (from the C++ runtime) like __cxa_allocate_exception
, __cxa_throw
, _Unwind_Resume
which is forbidden by signal(7)....
In practice, the only safe thing to do from a signal handler which does not abort
or _exit
is to set some volatile sigatomic_t
flag, or use the few async-signal-safe functions, e.g. write(2) something on a pipe(7). Also, throwing an exception from a signal handler is not worse than calling printf
from it (lots of people are wrongly doing it); it is forbidden, but it could often work. I still don't recommend doing that, in particular in programs which are running for a long time, or for which crashing -even infrequently- is not acceptable.
Read more about undefined behavior, notably Lattner's blog about What every C programmer should know about undefined behavior.
In practice, the only reliable and portable way to handle signals is to have a signal handler which just sets some volatile sigatomic_t
flag. But if you do that for SIGFPE
your implementation is very likely to restart the same computation in the same state, hence looping indefinitely on SIGFPE
handling. See also this regarding -fnon-call-exceptions
(so I believe that n.m.'s answer might not always be right and reliable; it is in fact undefined behavior which would often seem to work).
PS. Actually, I strongly suspect that Windows way of doing that conversion is not C++11 or C++14 standard (or C99 or C11 standard) conforming, and you could have a standard conforming implementation of C++ (or C99 or C11) on Windows which disallows doing what you suggest; and probably Clang or GCC are such implementations.

- 1
- 1

- 223,805
- 18
- 296
- 547
-
1The prohibition to call certain functions from sigbal handlers applies to user code written in C. It doesn't imply that an implementation itself cannot call such functions, or that it cannot guarantee safety of other functions not found in the POSIX list. – n. m. could be an AI Jul 07 '16 at 09:11
-
You could be right in theory, but in practice you are wrong, and SIGFPE can be called (on x86-64) by a integer zero divide which can happen everywhere (including in code implementing standard containers, for undefined behavior of them), and certainly in user code at *arbitrary point of machine code* – Basile Starynkevitch Jul 07 '16 at 09:13
-
You cannot blame -fnon-call-exceptions for inability to recover from UB caused by inappropriate code related to standard containers. It doesn't promise you that. As for user code, the point of -fnon-call-exceptions is to make it well-behaved in presence of exceptions caused by traps, including FPE traps. I don't care how the compiler does that. If you think the documentation doesn't promise that, file a bug against the documentation. It makes [many users](https://www.google.com/search?q=fnon-call-exceptions) believe that such promise exists. – n. m. could be an AI Jul 07 '16 at 09:49
-
You still are not saying what documentation does promise according to your interpretation. If it promises something, say what; if it promises nothing, perhaps file a bug about a useless switch. – n. m. could be an AI Jul 07 '16 at 09:49