mirror of https://github.com/golang/go.git
runtime: treat SI_TKILL like SI_USER on Linux
On Linux a signal sent using tgkill will have si_code == SI_TKILL, not SI_USER. Treat the two cases the same. Add a Linux-specific test. Change the test to use the C pause function rather than sleeping for a second, as that achieves the same effect. This is a roll forward of CL 431255 which was rolled back in CL 431715. This new version skips flaky tests on more systems, and marks a new method nosplit. Change-Id: Ibf2d3e6fc43d63d0a71afa8fcca6a11fda03f291 Reviewed-on: https://go-review.googlesource.com/c/go/+/432136 Auto-Submit: Ian Lance Taylor <iant@golang.org> Run-TryBot: Ian Lance Taylor <iant@golang.org> Reviewed-by: Bryan Mills <bcmills@google.com> Reviewed-by: Michael Pratt <mpratt@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
parent
fec83c8a7d
commit
d11c58eedb
|
|
@ -603,8 +603,14 @@ func TestSegv(t *testing.T) {
|
||||||
t.Skipf("no signals on %s", runtime.GOOS)
|
t.Skipf("no signals on %s", runtime.GOOS)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range []string{"Segv", "SegvInCgo"} {
|
for _, test := range []string{"Segv", "SegvInCgo", "TgkillSegv", "TgkillSegvInCgo"} {
|
||||||
test := test
|
test := test
|
||||||
|
|
||||||
|
// The tgkill variants only run on Linux.
|
||||||
|
if runtime.GOOS != "linux" && strings.HasPrefix(test, "Tgkill") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
t.Run(test, func(t *testing.T) {
|
t.Run(test, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
got := runTestProg(t, "testprogcgo", test)
|
got := runTestProg(t, "testprogcgo", test)
|
||||||
|
|
@ -633,10 +639,15 @@ func TestSegv(t *testing.T) {
|
||||||
testenv.SkipFlaky(t, 50979)
|
testenv.SkipFlaky(t, 50979)
|
||||||
}
|
}
|
||||||
|
|
||||||
nowant := "runtime: "
|
for _, nowant := range []string{"fatal error: ", "runtime: "} {
|
||||||
if strings.Contains(got, nowant) {
|
if strings.Contains(got, nowant) {
|
||||||
|
if runtime.GOOS == "darwin" && strings.Contains(got, "0xb01dfacedebac1e") {
|
||||||
|
// See the comment in signal_darwin_amd64.go.
|
||||||
|
t.Skip("skipping due to Darwin handling of malformed addresses")
|
||||||
|
}
|
||||||
t.Errorf("unexpectedly saw %q in output", nowant)
|
t.Errorf("unexpectedly saw %q in output", nowant)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -886,3 +886,17 @@ func runPerThreadSyscall() {
|
||||||
|
|
||||||
gp.m.needPerThreadSyscall.Store(0)
|
gp.m.needPerThreadSyscall.Store(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
_SI_USER = 0
|
||||||
|
_SI_TKILL = -6
|
||||||
|
)
|
||||||
|
|
||||||
|
// sigFromUser reports whether the signal was sent because of a call
|
||||||
|
// to kill or tgkill.
|
||||||
|
//
|
||||||
|
//go:nosplit
|
||||||
|
func (c *sigctxt) sigFromUser() bool {
|
||||||
|
code := int32(c.sigcode())
|
||||||
|
return code == _SI_USER || code == _SI_TKILL
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ package runtime
|
||||||
const (
|
const (
|
||||||
_SS_DISABLE = 2
|
_SS_DISABLE = 2
|
||||||
_NSIG = 65
|
_NSIG = 65
|
||||||
_SI_USER = 0
|
|
||||||
_SIG_BLOCK = 0
|
_SIG_BLOCK = 0
|
||||||
_SIG_UNBLOCK = 1
|
_SIG_UNBLOCK = 1
|
||||||
_SIG_SETMASK = 2
|
_SIG_SETMASK = 2
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ package runtime
|
||||||
const (
|
const (
|
||||||
_SS_DISABLE = 2
|
_SS_DISABLE = 2
|
||||||
_NSIG = 65
|
_NSIG = 65
|
||||||
_SI_USER = 0
|
|
||||||
_SIG_BLOCK = 0
|
_SIG_BLOCK = 0
|
||||||
_SIG_UNBLOCK = 1
|
_SIG_UNBLOCK = 1
|
||||||
_SIG_SETMASK = 2
|
_SIG_SETMASK = 2
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ func cputicks() int64 {
|
||||||
const (
|
const (
|
||||||
_SS_DISABLE = 2
|
_SS_DISABLE = 2
|
||||||
_NSIG = 129
|
_NSIG = 129
|
||||||
_SI_USER = 0
|
|
||||||
_SIG_BLOCK = 1
|
_SIG_BLOCK = 1
|
||||||
_SIG_UNBLOCK = 2
|
_SIG_UNBLOCK = 2
|
||||||
_SIG_SETMASK = 3
|
_SIG_SETMASK = 3
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ func cputicks() int64 {
|
||||||
const (
|
const (
|
||||||
_SS_DISABLE = 2
|
_SS_DISABLE = 2
|
||||||
_NSIG = 128 + 1
|
_NSIG = 128 + 1
|
||||||
_SI_USER = 0
|
|
||||||
_SIG_BLOCK = 1
|
_SIG_BLOCK = 1
|
||||||
_SIG_UNBLOCK = 2
|
_SIG_UNBLOCK = 2
|
||||||
_SIG_SETMASK = 3
|
_SIG_SETMASK = 3
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
// Copyright 2022 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
//go:build unix && !linux
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
// sigFromUser reports whether the signal was sent because of a call
|
||||||
|
// to kill.
|
||||||
|
//
|
||||||
|
//go:nosplit
|
||||||
|
func (c *sigctxt) sigFromUser() bool {
|
||||||
|
return c.sigcode() == _SI_USER
|
||||||
|
}
|
||||||
|
|
@ -662,7 +662,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
|
||||||
if sig < uint32(len(sigtable)) {
|
if sig < uint32(len(sigtable)) {
|
||||||
flags = sigtable[sig].flags
|
flags = sigtable[sig].flags
|
||||||
}
|
}
|
||||||
if c.sigcode() != _SI_USER && flags&_SigPanic != 0 && gp.throwsplit {
|
if !c.sigFromUser() && flags&_SigPanic != 0 && gp.throwsplit {
|
||||||
// We can't safely sigpanic because it may grow the
|
// We can't safely sigpanic because it may grow the
|
||||||
// stack. Abort in the signal handler instead.
|
// stack. Abort in the signal handler instead.
|
||||||
flags = _SigThrow
|
flags = _SigThrow
|
||||||
|
|
@ -672,7 +672,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
|
||||||
// causes a memory fault. Don't turn that into a panic.
|
// causes a memory fault. Don't turn that into a panic.
|
||||||
flags = _SigThrow
|
flags = _SigThrow
|
||||||
}
|
}
|
||||||
if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
|
if !c.sigFromUser() && flags&_SigPanic != 0 {
|
||||||
// The signal is going to cause a panic.
|
// The signal is going to cause a panic.
|
||||||
// Arrange the stack so that it looks like the point
|
// Arrange the stack so that it looks like the point
|
||||||
// where the signal occurred made a call to the
|
// where the signal occurred made a call to the
|
||||||
|
|
@ -690,13 +690,13 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
|
if c.sigFromUser() || flags&_SigNotify != 0 {
|
||||||
if sigsend(sig) {
|
if sigsend(sig) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.sigcode() == _SI_USER && signal_ignored(sig) {
|
if c.sigFromUser() && signal_ignored(sig) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -706,7 +706,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
|
||||||
|
|
||||||
// _SigThrow means that we should exit now.
|
// _SigThrow means that we should exit now.
|
||||||
// If we get here with _SigPanic, it means that the signal
|
// If we get here with _SigPanic, it means that the signal
|
||||||
// was sent to us by a program (c.sigcode() == _SI_USER);
|
// was sent to us by a program (c.sigFromUser() is true);
|
||||||
// in that case, if we didn't handle it in sigsend, we exit now.
|
// in that case, if we didn't handle it in sigsend, we exit now.
|
||||||
if flags&(_SigThrow|_SigPanic) == 0 {
|
if flags&(_SigThrow|_SigPanic) == 0 {
|
||||||
return
|
return
|
||||||
|
|
@ -929,7 +929,7 @@ func raisebadsignal(sig uint32, c *sigctxt) {
|
||||||
//
|
//
|
||||||
// On FreeBSD, the libthr sigaction code prevents
|
// On FreeBSD, the libthr sigaction code prevents
|
||||||
// this from working so we fall through to raise.
|
// this from working so we fall through to raise.
|
||||||
if GOOS != "freebsd" && (isarchive || islibrary) && handler == _SIG_DFL && c.sigcode() != _SI_USER {
|
if GOOS != "freebsd" && (isarchive || islibrary) && handler == _SIG_DFL && !c.sigFromUser() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1110,7 +1110,7 @@ func sigfwdgo(sig uint32, info *siginfo, ctx unsafe.Pointer) bool {
|
||||||
// Unfortunately, user generated SIGPIPEs will also be forwarded, because si_code
|
// Unfortunately, user generated SIGPIPEs will also be forwarded, because si_code
|
||||||
// is set to _SI_USER even for a SIGPIPE raised from a write to a closed socket
|
// is set to _SI_USER even for a SIGPIPE raised from a write to a closed socket
|
||||||
// or pipe.
|
// or pipe.
|
||||||
if (c.sigcode() == _SI_USER || flags&_SigPanic == 0) && sig != _SIGPIPE {
|
if (c.sigFromUser() || flags&_SigPanic == 0) && sig != _SIGPIPE {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// Determine if the signal occurred inside Go code. We test that:
|
// Determine if the signal occurred inside Go code. We test that:
|
||||||
|
|
|
||||||
|
|
@ -2,18 +2,16 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build !plan9 && !windows
|
//go:build unix
|
||||||
// +build !plan9,!windows
|
// +build unix
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
// #include <unistd.h>
|
||||||
// static void nop() {}
|
// static void nop() {}
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
import (
|
import "syscall"
|
||||||
"syscall"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
register("Segv", Segv)
|
register("Segv", Segv)
|
||||||
|
|
@ -35,8 +33,8 @@ func Segv() {
|
||||||
|
|
||||||
syscall.Kill(syscall.Getpid(), syscall.SIGSEGV)
|
syscall.Kill(syscall.Getpid(), syscall.SIGSEGV)
|
||||||
|
|
||||||
// Give the OS time to deliver the signal.
|
// Wait for the OS to deliver the signal.
|
||||||
time.Sleep(time.Second)
|
C.pause()
|
||||||
}
|
}
|
||||||
|
|
||||||
func SegvInCgo() {
|
func SegvInCgo() {
|
||||||
|
|
@ -52,6 +50,6 @@ func SegvInCgo() {
|
||||||
|
|
||||||
syscall.Kill(syscall.Getpid(), syscall.SIGSEGV)
|
syscall.Kill(syscall.Getpid(), syscall.SIGSEGV)
|
||||||
|
|
||||||
// Give the OS time to deliver the signal.
|
// Wait for the OS to deliver the signal.
|
||||||
time.Sleep(time.Second)
|
C.pause()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,51 @@
|
||||||
|
// Copyright 2022 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
// #include <unistd.h>
|
||||||
|
// static void nop() {}
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
register("TgkillSegv", TgkillSegv)
|
||||||
|
register("TgkillSegvInCgo", TgkillSegvInCgo)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TgkillSegv() {
|
||||||
|
c := make(chan bool)
|
||||||
|
go func() {
|
||||||
|
close(c)
|
||||||
|
for i := 0; ; i++ {
|
||||||
|
// Sum defined in segv.go.
|
||||||
|
Sum += i
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
<-c
|
||||||
|
|
||||||
|
syscall.Tgkill(syscall.Getpid(), syscall.Gettid(), syscall.SIGSEGV)
|
||||||
|
|
||||||
|
// Wait for the OS to deliver the signal.
|
||||||
|
C.pause()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TgkillSegvInCgo() {
|
||||||
|
c := make(chan bool)
|
||||||
|
go func() {
|
||||||
|
close(c)
|
||||||
|
for {
|
||||||
|
C.nop()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
<-c
|
||||||
|
|
||||||
|
syscall.Tgkill(syscall.Getpid(), syscall.Gettid(), syscall.SIGSEGV)
|
||||||
|
|
||||||
|
// Wait for the OS to deliver the signal.
|
||||||
|
C.pause()
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue