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:

Solution - desired

  1. 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)

  2. 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

Most upvoted comments

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.