runtime: forward crashing signals to late handlers

CL 49590 made it possible for external signal handlers to catch
signals from a crashing Go process. This CL extends that support
to handlers registered after the Go runtime has initialized.

Updates #20392 (and possibly fix it).

Change-Id: I18eccd5e958a505f4d1782a7fc51c16bd3a4ff9c
Reviewed-on: https://go-review.googlesource.com/57291
Run-TryBot: Elias Naur <elias.naur@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
Elias Naur 2017-08-19 16:59:19 +02:00
parent 176cd48e57
commit c3189cee71
13 changed files with 107 additions and 106 deletions

View file

@ -405,13 +405,8 @@ func sigpanic() {
//go:nowritebarrierrec
func dieFromSignal(sig uint32) {
unblocksig(sig)
// First, try any signal handler installed before the runtime
// initialized.
fn := atomic.Loaduintptr(&fwdSig[sig])
// On Darwin, sigtramp is called even for non-Go signal handlers.
// Mark the signal as unhandled to ensure it is forwarded.
atomic.Store(&handlingSig[sig], 0)
setsig(sig, fn)
raise(sig)
// That should have killed us. On some systems, though, raise
@ -601,17 +596,23 @@ func sigfwdgo(sig uint32, info *siginfo, ctx unsafe.Pointer) bool {
return false
}
fwdFn := atomic.Loaduintptr(&fwdSig[sig])
flags := sigtable[sig].flags
if !signalsOK {
// The only way we can get here is if we are in a
// library or archive, we installed a signal handler
// at program startup, but the Go runtime has not yet
// been initialized.
if fwdFn == _SIG_DFL {
dieFromSignal(sig)
} else {
sigfwd(fwdFn, sig, info, ctx)
// If we aren't handling the signal, forward it.
if atomic.Load(&handlingSig[sig]) == 0 || !signalsOK {
// If the signal is ignored, doing nothing is the same as forwarding.
if fwdFn == _SIG_IGN || (fwdFn == _SIG_DFL && flags&_SigIgn != 0) {
return true
}
// We are not handling the signal and there is no other handler to forward to.
// Crash with the default behavior.
if fwdFn == _SIG_DFL {
setsig(sig, _SIG_DFL)
dieFromSignal(sig)
return false
}
sigfwd(fwdFn, sig, info, ctx)
return true
}
@ -620,18 +621,6 @@ func sigfwdgo(sig uint32, info *siginfo, ctx unsafe.Pointer) bool {
return false
}
// If we aren't handling the signal, forward it.
// Really if we aren't handling the signal, we shouldn't get here,
// but on Darwin setsigstack can lead us here because it sets
// the sa_tramp field. The sa_tramp field is not returned by
// sigaction, so the fix for that is non-obvious.
if atomic.Load(&handlingSig[sig]) == 0 {
sigfwd(fwdFn, sig, info, ctx)
return true
}
flags := sigtable[sig].flags
c := &sigctxt{info, ctx}
// Only forward synchronous signals and SIGPIPE.
// Unfortunately, user generated SIGPIPEs will also be forwarded, because si_code