I just informed myselve about \"signals\" in C/C++ and played around. But i have a problem to understand the logic of SIGFPE
.
I wrote a little program which
As I commented, most signals are OS specific. For Linux, read carefully signal(7). You forgot a \n
inside your printf
(usually, you'll be lucky enough to see something work in your code, but read all my answer). And in principle you should not call printf
(which is not an async-signal-safe function, you should use directly and only write(2) inside) from your signal handler.
What probably is happening is (ignoring the undefined behavior posed by wrongly using printf
inside the signal handler) is that:
your stdout
buffer is never flushed since you forgot a \n
(you might add a fflush(NULL);
...) in the printf
inside my_handler
in your code
probably, the SIGFPE handler restarts again the machine code instruction triggering it. (More exactly, after returning from sigreturn(2) your machine is in the same state as it was before SIGFPE
was delivered, so the same divide-by-zero condition happens, etc...)
It is difficult (but painfully possible, if you accept coding hardware-specific and operating-system specific code) to handle SIGFPE
; you would use sigaction(2) with SA_SIGINFO
and handle the third argument to the signal handler (which is a ucontext_t
pointer indirectly giving the machine state, including processor registers, which you might change inside your handler; in particular you could change your return program counter there). You might also consider using sigsetjmp(3) inside your signal handler (but it is in theory forbidden, since not async-signal-safe).
(You certainly need to understand the details of your processor's instruction set architecture and your operating system's ABI; and you probably would need a week of coding work after having mastered these)
In a portable POSIX way, SIGFPE
cannot really be handled, as explained in Blue Moon's answer
Probably, the runtime of JVM or of SBCL is handling SIGFPE
in a machine & operating system specific way to report zero-divides as divide-by-zero exceptions .... (to Java programs for JVM, to Common Lisp programs for SBCL). Alternatively their JIT or compiler machinery could generate a test before every division.
BTW, a flag set inside a signal handler should be declared volatile sig_atomic_t
. See POSIX specification about <signal.h>
As a pragmatical rule of thumb, a POSIX portable and robust signal handler should only set some volatile sig_atomic_t
and/or perhaps write(2) a few bytes to some pipe(7) (your process could set up a pipe to itself -as recommended by Qt-, with another thread and/or some event loop reading it), but this does not work for asynchronous process-generated signals like SIGFPE
, SIGBUS
, SIGILL
, and SIGSEGV
, etc... (which could only be handled by painful computer-specific code).
See also this answer to a very related question.
At last, on Linux, signal processing is believed to be not very quick. Even with a lot of machine-specific coding, emulating GNU Hurd external pagers by tricky SIGSEGV
handling (which would mmap
lazily ....) is believed to be quite slow.
Divide by zero is undefined behaviour. So whether you have installed a handler for SIGFPE
or not is of little significance when your program invokes undefined behaviour.
POSIX says:
Delivery of the signal shall have no effect on the process. The behavior of a process is undefined after it ignores a SIGFPE, SIGILL, SIGSEGV, or SIGBUS signal that was not generated by kill(), sigqueue(), or raise().
A signal is raised as a result of an event (e.g. sending SIGINT
by pressing CTRL+C) which can be handled by the process if said event non-fatal. SIGFPE
is an erroneous condition in the program and you can't handle that. A similar case would be attempting to handle SIGSEGV
, which is equivalent to this (undefined behaviour). When your process attempts to access some memory for which it doesn't have access. It would be silly if you could just ignore it and carry on as if nothing happened.