How to use SIGFPE with signal?

后端 未结 2 1979
天涯浪人
天涯浪人 2021-01-27 13:55

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

相关标签:
2条回答
  • 2021-01-27 14:13

    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.

    0 讨论(0)
  • 2021-01-27 14:22

    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.

    0 讨论(0)
提交回复
热议问题