How to use SIGFPE with signal?

后端 未结 2 2006
天涯浪人
天涯浪人 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

    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.

提交回复
热议问题