I agree with the comments: in practice catching and handling SIGSEGV
is often a bad thing.
And SIGSEGV
is delivered to a specific thread (see this), the one running the machine instruction which accessed to some illegal address.
So you cannot run a thread dedicated to catching SIGSEGV
in other threads. And you probably could not easily use signalfd(2) for SIGSEGV
...
Catching (and returning normally from its signal handler) SIGSEGV
is a complex and processor specific thing (it cannot be "portable C code"). You need to inspect and alter the machine state in the handler, that is either modify the address space (by calling mmap(2) etc...) or modify the register state of the current thread. So use sigaction(2) with SA_SIGINFO
and change the machine specific state pointed by the third argument (of type ucontext_t*
) of the signal handler. Then dive into the processor specific uc_mcontext
field of it. Have fun changing individual registers, etc... If you don't alter the machine state of the faulty thread, execution is resumed (after returning from your SIGSEGV
handler) in the same situation as before, and another SIGSEGV
signal is immediately sent.... Or simply, don't return normally from a SIGSEGV
handler (e.g. use siglongjmp(3) or abort(3) or _exit(2) ...).
Even if you happen to do all this, it is rumored that Linux kernels are not extremely efficient on such executions. So it is rumored that trying to mimic Hurd/Mach external pagers this way on Linux is not very efficient. See this answer...
Of course signal handlers should call only (see signal(7) for more) async-signal-safe functions. In particular, you cannot in principle call fprintf
from them (and you might not be able to use reliably your logging system, but it could work in most but not all cases).
What I said on SIGSEGV
also holds for SIGBUS
and SIGFPE
(and other thread-specific asynchronous signals, if they exist).
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…