]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: treat SI_TKILL like SI_USER on Linux
authorIan Lance Taylor <iant@golang.org>
Thu, 15 Sep 2022 18:33:58 +0000 (11:33 -0700)
committerGopher Robot <gobot@golang.org>
Sat, 17 Sep 2022 01:41:08 +0000 (01:41 +0000)
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.

Change-Id: I2a36646aecabcab9ec42ed9a048b07c2ff0a3987
Reviewed-on: https://go-review.googlesource.com/c/go/+/431255
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Ian Lance Taylor <iant@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>

src/runtime/crash_cgo_test.go
src/runtime/os_linux.go
src/runtime/os_linux_be64.go
src/runtime/os_linux_generic.go
src/runtime/os_linux_mips64x.go
src/runtime/os_linux_mipsx.go
src/runtime/os_unix_nonlinux.go [new file with mode: 0644]
src/runtime/signal_unix.go
src/runtime/testdata/testprogcgo/segv.go
src/runtime/testdata/testprogcgo/segv_linux.go [new file with mode: 0644]

index 5e5871229729ef1de41a44853668a7d7cf684d4e..f0a27507b906f09f831c515a9b4137140fe2b202 100644 (file)
@@ -603,8 +603,14 @@ func TestSegv(t *testing.T) {
                t.Skipf("no signals on %s", runtime.GOOS)
        }
 
-       for _, test := range []string{"Segv", "SegvInCgo"} {
+       for _, test := range []string{"Segv", "SegvInCgo", "TgkillSegv", "TgkillSegvInCgo"} {
                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.Parallel()
                        got := runTestProg(t, "testprogcgo", test)
@@ -617,6 +623,15 @@ func TestSegv(t *testing.T) {
                                t.Errorf("did not see %q in output", want)
                        }
 
+                       doNotWant := "fatal error:"
+                       if strings.Contains(got, doNotWant) {
+                               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("saw %q in output", doNotWant)
+                       }
+
                        // No runtime errors like "runtime: unknown pc".
                        switch runtime.GOOS {
                        case "darwin", "illumos", "solaris":
index 3ae665c83d867a923223ea52156e2763eceaa757..e84f065e24f4dcabfa63aa4b1d64f9e9d28e8657 100644 (file)
@@ -886,3 +886,15 @@ func runPerThreadSyscall() {
 
        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.
+func (c *sigctxt) sigFromUser() bool {
+       code := int32(c.sigcode())
+       return code == _SI_USER || code == _SI_TKILL
+}
index 537515fcf25a8f166a4e043a828f3348d2af9c4d..d8d4ac2497f4ecd126b1cd19dbd30dad20e19fd8 100644 (file)
@@ -11,7 +11,6 @@ package runtime
 const (
        _SS_DISABLE  = 2
        _NSIG        = 65
-       _SI_USER     = 0
        _SIG_BLOCK   = 0
        _SIG_UNBLOCK = 1
        _SIG_SETMASK = 2
index bed9e66e156e2c72e1cd30f71b40fb790343908d..15fafc14eab16bb8aeeca005d5cb18f85e9fec2c 100644 (file)
@@ -9,7 +9,6 @@ package runtime
 const (
        _SS_DISABLE  = 2
        _NSIG        = 65
-       _SI_USER     = 0
        _SIG_BLOCK   = 0
        _SIG_UNBLOCK = 1
        _SIG_SETMASK = 2
index 188db0103481d769d0c96d57b59a3bcad4fdc64c..11d35bc0204a2f7293e91d9ca8229909b1e3cff5 100644 (file)
@@ -27,7 +27,6 @@ func cputicks() int64 {
 const (
        _SS_DISABLE  = 2
        _NSIG        = 129
-       _SI_USER     = 0
        _SIG_BLOCK   = 1
        _SIG_UNBLOCK = 2
        _SIG_SETMASK = 3
index 73016f81d91b7c8beb375870f63acf2f2bb84448..cdf83ff71dda01d48a7ed0fd8d5647f58b7ae351 100644 (file)
@@ -21,7 +21,6 @@ func cputicks() int64 {
 const (
        _SS_DISABLE  = 2
        _NSIG        = 128 + 1
-       _SI_USER     = 0
        _SIG_BLOCK   = 1
        _SIG_UNBLOCK = 2
        _SIG_SETMASK = 3
diff --git a/src/runtime/os_unix_nonlinux.go b/src/runtime/os_unix_nonlinux.go
new file mode 100644 (file)
index 0000000..5c8a137
--- /dev/null
@@ -0,0 +1,13 @@
+// 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.
+func (c *sigctxt) sigFromUser() bool {
+       return c.sigcode() == _SI_USER
+}
index 545094c6403180985d86bec2fa6a7999220ae939..4c55e837477c6ec5d1d43ea02339f400a0e4e06f 100644 (file)
@@ -662,7 +662,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
        if sig < uint32(len(sigtable)) {
                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
                // stack. Abort in the signal handler instead.
                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.
                flags = _SigThrow
        }
-       if c.sigcode() != _SI_USER && flags&_SigPanic != 0 {
+       if !c.sigFromUser() && flags&_SigPanic != 0 {
                // The signal is going to cause a panic.
                // Arrange the stack so that it looks like the point
                // 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
        }
 
-       if c.sigcode() == _SI_USER || flags&_SigNotify != 0 {
+       if c.sigFromUser() || flags&_SigNotify != 0 {
                if sigsend(sig) {
                        return
                }
        }
 
-       if c.sigcode() == _SI_USER && signal_ignored(sig) {
+       if c.sigFromUser() && signal_ignored(sig) {
                return
        }
 
@@ -706,7 +706,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
 
        // _SigThrow means that we should exit now.
        // 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.
        if flags&(_SigThrow|_SigPanic) == 0 {
                return
@@ -929,7 +929,7 @@ func raisebadsignal(sig uint32, c *sigctxt) {
        //
        // On FreeBSD, the libthr sigaction code prevents
        // 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
        }
 
@@ -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
        // is set to _SI_USER even for a SIGPIPE raised from a write to a closed socket
        // or pipe.
-       if (c.sigcode() == _SI_USER || flags&_SigPanic == 0) && sig != _SIGPIPE {
+       if (c.sigFromUser() || flags&_SigPanic == 0) && sig != _SIGPIPE {
                return false
        }
        // Determine if the signal occurred inside Go code. We test that:
index 0632475228d9b0c709098b3d616f9ebf53c18ebc..bf5aa313b303f81a2ec74c1c43ff7410c6c94213 100644 (file)
@@ -2,18 +2,16 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build !plan9 && !windows
-// +build !plan9,!windows
+//go:build unix
+// +build unix
 
 package main
 
+// #include <unistd.h>
 // static void nop() {}
 import "C"
 
-import (
-       "syscall"
-       "time"
-)
+import "syscall"
 
 func init() {
        register("Segv", Segv)
@@ -35,8 +33,8 @@ func Segv() {
 
        syscall.Kill(syscall.Getpid(), syscall.SIGSEGV)
 
-       // Give the OS time to deliver the signal.
-       time.Sleep(time.Second)
+       // Wait for the OS to deliver the signal.
+       C.pause()
 }
 
 func SegvInCgo() {
@@ -52,6 +50,6 @@ func SegvInCgo() {
 
        syscall.Kill(syscall.Getpid(), syscall.SIGSEGV)
 
-       // Give the OS time to deliver the signal.
-       time.Sleep(time.Second)
+       // Wait for the OS to deliver the signal.
+       C.pause()
 }
diff --git a/src/runtime/testdata/testprogcgo/segv_linux.go b/src/runtime/testdata/testprogcgo/segv_linux.go
new file mode 100644 (file)
index 0000000..fe93778
--- /dev/null
@@ -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()
+}