]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: handle async fatal signals in VDSO
authorMichael Pratt <mpratt@google.com>
Wed, 4 Aug 2021 21:33:50 +0000 (17:33 -0400)
committerMichael Pratt <mpratt@google.com>
Tue, 26 Oct 2021 21:32:57 +0000 (21:32 +0000)
If we receive an async signal while running in the VDSO, such as a
SIGABRT or SIGSEGV sent from another process, we fail to print the
stacktrace with "runtime: unknown pc <vdso PC>".

We already have machinery to handle SIGPROF in the VDSO, but it isn't
hooked up for other signals. Add it to the general signal traceback
path.

This case is covered by TestSegv by making the test more strict w.r.t.
accepted output.

Fixes #47537

Change-Id: I755585f70e0c23e207e135bc6bd2aa68298e5d24
Reviewed-on: https://go-review.googlesource.com/c/go/+/339990
Trust: Michael Pratt <mpratt@google.com>
Run-TryBot: Michael Pratt <mpratt@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
src/runtime/crash_cgo_test.go
src/runtime/traceback.go

index 9df6fcd48b95aabf98a3657d578176d59f573ae4..0ccfe8580adf1e8c6a477e89e92767cbf747c10e 100644 (file)
@@ -526,13 +526,15 @@ func TestCgoTracebackSigpanic(t *testing.T) {
        }
        t.Parallel()
        got := runTestProg(t, "testprogcgo", "TracebackSigpanic")
+       t.Log(got)
        want := "runtime.sigpanic"
        if !strings.Contains(got, want) {
-               t.Fatalf("want failure containing %q. output:\n%s\n", want, got)
+               t.Errorf("did not see %q in output", want)
        }
-       nowant := "unexpected return pc"
+       // No runtime errors like "runtime: unexpected return pc".
+       nowant := "runtime: "
        if strings.Contains(got, nowant) {
-               t.Fatalf("failure incorrectly contains %q. output:\n%s\n", nowant, got)
+               t.Errorf("unexpectedly saw %q in output", want)
        }
 }
 
@@ -619,8 +621,14 @@ func TestSegv(t *testing.T) {
                        t.Parallel()
                        got := runTestProg(t, "testprogcgo", test)
                        t.Log(got)
-                       if !strings.Contains(got, "SIGSEGV") {
-                               t.Errorf("expected crash from signal")
+                       want := "SIGSEGV"
+                       if !strings.Contains(got, want) {
+                               t.Errorf("did not see %q in output", want)
+                       }
+                       // No runtime errors like "runtime: unknown pc".
+                       nowant := "runtime: "
+                       if strings.Contains(got, nowant) {
+                               t.Errorf("unexpectedly saw %q in output", want)
                        }
                })
        }
index 530d572095b987d74fc78e0f4846b37c08fda5c6..7e1b14ccf29fb233088909724dc786aa9a13023b 100644 (file)
@@ -777,16 +777,23 @@ func traceback1(pc, sp, lr uintptr, gp *g, flags uint) {
                printCgoTraceback(&cgoCallers)
        }
 
-       var n int
        if readgstatus(gp)&^_Gscan == _Gsyscall {
                // Override registers if blocked in system call.
                pc = gp.syscallpc
                sp = gp.syscallsp
                flags &^= _TraceTrap
        }
+       if gp.m != nil && gp.m.vdsoSP != 0 {
+               // Override registers if running in VDSO. This comes after the
+               // _Gsyscall check to cover VDSO calls after entersyscall.
+               pc = gp.m.vdsoPC
+               sp = gp.m.vdsoSP
+               flags &^= _TraceTrap
+       }
+
        // Print traceback. By default, omits runtime frames.
        // If that means we print nothing at all, repeat forcing all frames printed.
-       n = gentraceback(pc, sp, lr, gp, 0, nil, _TracebackMaxFrames, nil, nil, flags)
+       n := gentraceback(pc, sp, lr, gp, 0, nil, _TracebackMaxFrames, nil, nil, flags)
        if n == 0 && (flags&_TraceRuntimeFrames) == 0 {
                n = gentraceback(pc, sp, lr, gp, 0, nil, _TracebackMaxFrames, nil, nil, flags|_TraceRuntimeFrames)
        }