runtime: handle SIGPIPE in c-archive and c-shared programs

Before this CL, Go programs in c-archive or c-shared buildmodes
would not handle SIGPIPE. That leads to surprising behaviour where
writes on a closed pipe or socket would raise SIGPIPE and terminate
the program. This CL changes the Go runtime to handle
SIGPIPE regardless of buildmode. In addition, SIGPIPE from non-Go
code is forwarded.

Fixes #17393
Updates #16760

Change-Id: I155e82020a03a5cdc627a147c27da395662c3fe8
Reviewed-on: https://go-review.googlesource.com/32796
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 2016-11-06 21:40:57 +01:00 committed by Ian Lance Taylor
parent e54662dc85
commit d24b57a6a1
8 changed files with 136 additions and 9 deletions

View file

@ -111,8 +111,8 @@ func sigInstallGoHandler(sig uint32) bool {
}
// When built using c-archive or c-shared, only install signal
// handlers for synchronous signals.
if (isarchive || islibrary) && t.flags&_SigPanic == 0 {
// handlers for synchronous signals and SIGPIPE.
if (isarchive || islibrary) && t.flags&_SigPanic == 0 && sig != _SIGPIPE {
return false
}
@ -492,9 +492,15 @@ func sigfwdgo(sig uint32, info *siginfo, ctx unsafe.Pointer) bool {
return true
}
// Only forward synchronous signals.
c := &sigctxt{info, ctx}
if c.sigcode() == _SI_USER || flags&_SigPanic == 0 {
// Only forward signals from the kernel.
// On Linux and Darwin there is no way to distinguish a SIGPIPE raised by a write
// to a closed socket or pipe from a SIGPIPE raised by kill or pthread_kill
// so we'll treat every SIGPIPE as kernel-generated.
userSig := c.sigcode() == _SI_USER &&
(sig != _SIGPIPE || GOOS != "linux" && GOOS != "android" && GOOS != "darwin")
// Only forward synchronous signals and SIGPIPE.
if userSig || flags&_SigPanic == 0 && sig != _SIGPIPE {
return false
}
// Determine if the signal occurred inside Go code. We test that: