-
Notifications
You must be signed in to change notification settings - Fork 18.5k
Description
What version of Go are you using (go version)?
$ go version go version devel go1.21-9222a01e65 Fri Feb 3 04:37:17 2023 +0000 darwin/amd64
Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (go env)?
go env Output
$ go env GO111MODULE="" GOARCH="amd64" GOBIN="" GOCACHE="/Users/korniltsev/Library/Caches/go-build" GOENV="/Users/korniltsev/Library/Application Support/go/env" GOEXE="" GOEXPERIMENT="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="darwin" GOINSECURE="" GOMODCACHE="/Users/korniltsev/go/pkg/mod" GONOPROXY="" GONOSUMDB="" GOOS="darwin" GOPATH="/Users/korniltsev/go" GOPRIVATE="" GOPROXY="https://proxy.golang.org,direct" GOROOT="/Users/korniltsev/github/go-darwin-amd64-bootstrap" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/Users/korniltsev/github/go-darwin-amd64-bootstrap/pkg/tool/darwin_amd64" GOVCS="" GOVERSION="devel go1.21-9222a01e65 Fri Feb 3 04:37:17 2023 +0000" GCCGO="gccgo" GOAMD64="v1" AR="ar" CC="clang" CXX="clang++" CGO_ENABLED="1" GOMOD="/Users/korniltsev/github/go/src/go.mod" GOWORK="" CGO_CFLAGS="-O2 -g" CGO_CPPFLAGS="" CGO_CXXFLAGS="-O2 -g" CGO_FFLAGS="-O2 -g" CGO_LDFLAGS="-O2 -g" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -arch x86_64 -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/2t/v1n4q5yj48315c_ccftr_d_c0000gn/T/go-build2988258767=/tmp/go-build -gno-record-gcc-switches -fno-common"
What did you do?
I noticed an inconsistency in handling inline wrapper functions between runtime_expandFinalInlineFrame and gentraceback.
gentraceback ignores a wrapper function with an inlined function and runtime_expandFinalInlineFrame does not ignore and append to stacktrace. Because of that profileBuilder.appendLocsForStack may emit different locations for exactly the same stack, depending on the order of processed records. For example if a builder sees a wrapped function for the first time as a last item in the stack, it will be expanded with an extra pc of a wrapped function and emit a location with two functions. At the same time if a builder sees a wrapped function for the first time in the middle of the stack, it will emit a location with one function.
In order to reproduce the issue with pprof profiles you need to have a profile sample with a stacktrace ending(truncated) with a wrapper function(for example a heap profile with a stack[31] pointing to a wrapped inlined function).
An easier way to reproduce the inconsistency calling runtime_expandFinalInlineFrame directly:
https://go.dev/play/p/FW8j4zXCrqN
What did you expect to see?
======== stack ========
108a6f3 runtime.Callers
108a6dd main.stackHandler.handle
108a0d2 main.main
1031127 runtime.main
105ad21 runtime.goexit
======== truncated ========
108a6f3 runtime.Callers
108a6dd main.stackHandler.handle
======== expanded ========
108a6f3 runtime.Callers
108a6dd main.stackHandler.handle
What did you see instead?
======== stack ========
108a6d3 runtime.Callers
108a6bd main.stackHandler.handle
108a0b2 main.main
1031127 runtime.main
105ad01 runtime.goexit
======== truncated ========
108a6d3 runtime.Callers
108a6bd main.stackHandler.handle
======== expanded ========
108a6d3 runtime.Callers
108a6bd main.stackHandler.handle
108a6b8 main.(*stackHandler).handle
Possible fix
diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go
index dead27e5f2..da83fd93ea 100644
--- a/src/runtime/symtab.go
+++ b/src/runtime/symtab.go
@@ -230,7 +230,11 @@ func runtime_expandFinalInlineFrame(stk []uintptr) []uintptr {
}
// N.B. we want to keep the last parentPC which is not inline.
- stk = append(stk, pc)
+ if f.funcID == funcID_wrapper && elideWrapperCalling(lastFuncID) {
+ // Ignore wrapper functions (except when they trigger panics).
+ } else {
+ stk = append(stk, pc)
+ }
return stk
}CC @prattmic