1
0
mirror of https://github.com/golang/go synced 2024-11-17 08:14:48 -07:00

runtime: fix callee tracking in traceback printing

In CL 466099, we accidentally stopped tracking callees while unwinding
inlined frames during traceback printing. The effect is that if you
have a call stack like:

  f -> wrapper -> inlined into wrapper -> panic

when considering whether to print the frame for "wrapper", we'll think
that wrapper called panic, rather than the inlined function.

Fix this in the traceback code and add a test.

Change-Id: I30ec836cc316846ce93de94e28a650e23dca184e
Reviewed-on: https://go-review.googlesource.com/c/go/+/476579
Run-TryBot: Austin Clements <austin@google.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Michael Pratt <mpratt@google.com>
This commit is contained in:
Austin Clements 2023-03-15 14:27:10 -04:00
parent be27fcfd2b
commit 5f62ba621e
2 changed files with 33 additions and 1 deletions

View File

@ -6,6 +6,7 @@ package runtime_test
import (
"fmt"
"internal/testenv"
"reflect"
"regexp"
. "runtime"
@ -652,6 +653,8 @@ func (s structWithMethod) stack() string {
func (s structWithMethod) nop() {}
func (s structWithMethod) inlinablePanic() { panic("panic") }
func TestStackWrapperCaller(t *testing.T) {
var d structWithMethod
// Force the compiler to construct a wrapper method.
@ -689,6 +692,33 @@ func TestStackWrapperStack(t *testing.T) {
}
}
func TestStackWrapperStackInlinePanic(t *testing.T) {
// Test that inline unwinding correctly tracks the callee by creating a
// stack of the form wrapper -> inlined function -> panic. If we mess up
// callee tracking, it will look like the wrapper called panic and we'll see
// the wrapper in the stack trace.
var d structWithMethod
wrapper := (*structWithMethod).inlinablePanic
defer func() {
err := recover()
if err == nil {
t.Fatalf("expected panic")
}
buf := make([]byte, 4<<10)
stk := string(buf[:Stack(buf, false)])
if strings.Contains(stk, "<autogenerated>") {
t.Fatalf("<autogenerated> appears in stack trace:\n%s", stk)
}
// Self-check: make sure inlinablePanic got inlined.
if !testenv.OptimizationOff() {
if !strings.Contains(stk, "inlinablePanic(...)") {
t.Fatalf("inlinablePanic not inlined")
}
}
}()
wrapper(&d)
}
type I interface {
M()
}

View File

@ -845,7 +845,9 @@ func traceback2(u *unwinder, showRuntime bool) int {
f := u.frame.fn
for iu, uf := newInlineUnwinder(f, u.symPC(), noEscapePtr(&u.cache)); n < max && uf.valid(); uf = iu.next(uf) {
sf := iu.srcFunc(uf)
if !(showRuntime || showframe(sf, gp, n == 0, u.calleeFuncID)) {
callee := u.calleeFuncID
u.calleeFuncID = sf.funcID
if !(showRuntime || showframe(sf, gp, n == 0, callee)) {
continue
}