From 86f6bf18b013d570e89f57c2decaddca5ce2a847 Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Wed, 4 Aug 2021 17:33:50 -0400 Subject: [PATCH] runtime: handle async fatal signals in VDSO 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 ". 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 Run-TryBot: Michael Pratt TryBot-Result: Go Bot Reviewed-by: Cherry Mui --- src/runtime/crash_cgo_test.go | 18 +++++++++++++----- src/runtime/traceback.go | 11 +++++++++-- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/runtime/crash_cgo_test.go b/src/runtime/crash_cgo_test.go index 9df6fcd48b9..0ccfe8580ad 100644 --- a/src/runtime/crash_cgo_test.go +++ b/src/runtime/crash_cgo_test.go @@ -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) } }) } diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go index 530d572095b..7e1b14ccf29 100644 --- a/src/runtime/traceback.go +++ b/src/runtime/traceback.go @@ -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) }