go: runtime/cgo: can't safely use signal handling on Darwin, missing support from Go runtime
- Go version: 1.9
- Reproduces with latest release
- using Darwin/amd64 - this issue is not relevant to any other OS, but is perhaps relevant to other darwin platforms.
tl;dr: Problem: C’s standard sigaction
on Darwin cannot retrieve the current signal trampoline, therefore cgo code cannot properly restore the Go trampoline. Solution: document the problem and expose a C symbol for use by cgo code to restore Go’s signal configuration.
The following repository contains an example of the problem and an example of the manual, ugly solution (barring a clean solution provided by Go):
https://github.com/knz/sigtramp-bug
(Note: this code can only be compiled and run on a darwin system.)
What did you expect to see?
The following code, when called from cgo, should restore Go’s signal handler properly:
void test(void) {
struct sigaction act, oact;
// save go's signal handler
sigaction(SIGWINCH, 0, &oact);
// this code is irrelevant
act.sa_flags = SA_RESTART|SA_ONSTACK; // as per go docs
act.sa_handler = xxx;
sigaction(SIGWINCH, &act, 0);
// end of irrelevant code
// restore go's signal handler
sigaction(SIGWINCH, &oact, 0);
}
The final sigaction
call in the code above should ensure that the values saved at the beginning are restored, and thus that any change by the C code is invisible to Go when the function returns.
What did you see instead?
See e.g. https://github.com/knz/sigtramp-bug/tree/master/cgo-failure
After the function completes, issuing the signal causes the following panic:
runtime: newstack sp=0xc420009be8 stack=[0xc42004e000, 0xc420050000]
morebuf={pc:0x7fff6b863f5a sp:0xc420009bf0 lr:0x0}
sched={pc:0x403a68a sp:0xc420009be8 lr:0x0 ctxt:0x0}
fatal error: runtime: stack split at bad time
Or sometimes also:
fatal: morestack on g0
Anyway, investigation reveals the following:
https://opensource.apple.com/source/Libc/Libc-1244.1.7/sys/sigaction.c.auto.html
In other words, sigaction
always overrides the trampoline with Apple’s own _sigtramp
. Go’s runtime.sigtramp
is lost.
Moreover, the underlying syscall __sigaction
can set but not retrieve the signal handler (see declaration in the same file: the oact
argument has type struct sigaction
not struct __sigaction
).
This is arguably a bug/misfeature on Apple’s side.
Solution - manual
The manual solution is to manually re-inject Go’s own runtime.sigtramp
in the signal configuration, as done here:
https://github.com/knz/sigtramp-bug/tree/master/cgo-fix
This is cumbersome because:
runtime.sigtramp
is not exported, so one has to jump hoops to retrieve it: https://github.com/knz/go-libedit/tree/master/unix/sigtramp- we’re relying on a non-public syscall wrapper in Apple’s C library (
__sigaction
), which is not guaranteed to stay over time.
Solution - desired
-
the Go docs about Cgo should say "a program that wishes to temporarily set signal handler and then restore Go’s signal configuration must use a function
sigrestore
provided by the Go runtime` (or alternatively a pair sigsave/sigrestore) -
the Go runtime should provide the corresponding (
sigsave
/)sigrestore
function for use by Cgo code.
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Comments: 17 (10 by maintainers)
Commits related to this issue
- runtime: use libc's signal functions on Darwin sigaction, sigprocmask, sigaltstack, and raiseproc. Fix bug in mstart_stub where we weren't saving callee-saved registers, so if an m finished the pthr... — committed to golang/go by randall77 6 years ago
- Don't install signal handler when checking cpuid As part of its CPU feature detection, CryptoPP installs a SIGILL signal handler before issuing the cpuid instruction. The intent is to gracefully degr... — committed to cockroachdb/cryptopp by benesch 6 years ago
- Don't install signal handler when checking cpuid As part of its CPU feature detection, CryptoPP installs a SIGILL signal handler before issuing the cpuid instruction. The intent is to gracefully degr... — committed to cockroachdb/cryptopp by benesch 6 years ago
- c-deps: bump CryptoPP to avoid SIGTRAP on macOS Bump CryptoPP to pick up a fix for cockroachdb/cockroach#31380. Details reproduced below. Fix #31380. --- As part of its CPU feature detection, Cryp... — committed to benesch/cockroach by benesch 6 years ago
- Merge #31516 #31517 31516: c-deps: bump CryptoPP to avoid SIGTRAP on macOS r=mberhault a=benesch Bump CryptoPP to pick up a fix for cockroachdb/cockroach#31380. Details reproduced below. Fix #31... — committed to cockroachdb/cockroach by deleted user 6 years ago
- c-deps: bump CryptoPP to avoid SIGTRAP on macOS Bump CryptoPP to pick up a fix for cockroachdb/cockroach#31380. Details reproduced below. Fix #31380. --- As part of its CPU feature detection, Cryp... — committed to benesch/cockroach by benesch 6 years ago
- Don't install signal handler when checking cpuid As part of its CPU feature detection, CryptoPP installs a SIGILL signal handler before issuing the cpuid instruction. The intent is to gracefully degr... — committed to cockroachdb/cryptopp by benesch 6 years ago
- c-deps: bump CryptoPP to avoid SIGTRAP on macOS Bump CryptoPP to pick up a fix for cockroachdb/cockroach#31380. Details reproduced below. Fix #31380. --- As part of its CPU feature detection, Cryp... — committed to benesch/cockroach by benesch 6 years ago
If Go code always installs signal handlers using
sigaction
, then there will be no problem.Let’s fix #17490, which we have to fix anyhow, and then see where we are.