golang/go

runtime: dieFromSignal should reinstall fwdSig[sig] instead of hard-coding _SIG_DFL

bcmills opened this issue · 3 comments

runtime.dieFromSignal is called in a few places in the runtime where we've handled a fatal signal and intend to terminate the process.

At the moment, dieFromSignal unconditionally calls setsig(sig, _SIG_DFL) and re-raises the signal.
That's pretty much always the right thing to do in a pure-Go program.

However, in a mixed-language program there may be some existing signal handler, and that signal handler might want to do something useful — for example, save a core dump, mark an input record as a potential cause of the crash, or write an entry to a crash log.

It seems to me that we could address this use-case pretty easily by making dieFromSignal try to reinstall and raise to the previous handler before it resorts to SIG_DFL. Perhaps something like:

func dieFromSignal(sig uint32) {
	fwdFn := atomic.Loaduintptr(&fwdSig[sig])
	if fwdFn != _SIG_DFL {
		setsig(sig, fwdFn)
		unblocksig(sig)
		raise(sig)
	}

	// fwdSig[sig] either didn't exist or failed to terminate the process.
	// Try _SIG_DFL instead.
	setsig(sig, _SIG_DFL)
	unblocksig(sig)
	raise(sig)

	// That should have killed us. On some systems, though, raise
	// sends the signal to the whole process rather than to just
	// the current thread, which means that the signal may not yet
	// have been delivered. Give other threads a chance to run and
	// pick up the signal.
	osyield()
	osyield()
	osyield()

	// If we are still somehow running, just exit with the wrong status.
	exit(2)
}

In the typical case — when there are no handlers registered before ours — the behavior would be the same as it is today. On the off chance that some other language has registered a prior handler, we would instead invoke that handler, and if it isn't well behaved (i.e. doesn't terminate the process), then we fall back to today's behavior anyway.

SGTM

It's only necessary to call unblockSig once.

CL https://golang.org/cl/49590 mentions this issue.

Change https://golang.org/cl/55032 mentions this issue: runtime: fix crashing with foreign signal handlers on Darwin