Skip to content

internal/report: fall back to $GOROOT/src when locating source files - #1010

Open
jespino wants to merge 3 commits into
google:mainfrom
jespino:stack/1-goroot
Open

internal/report: fall back to $GOROOT/src when locating source files#1010
jespino wants to merge 3 commits into
google:mainfrom
jespino:stack/1-goroot

Conversation

@jespino

@jespino jespino commented Jul 20, 2026

Copy link
Copy Markdown

Profiles from Go programs refer to standard library sources under the GOROOT of the build machine, which breaks the source and weblist views when that path does not exist locally (e.g. a profile from another machine), or when the program was built with -trimpath and the files are recorded relative to $GOROOT/src.

Teach openSourceFile to fall back to the local $GOROOT/src after the regular search fails: relative paths resolve against it directly, and absolute paths resolve by matching the components after a /src/ one. The fallback only runs when the existing lookup finds nothing, so previously resolved files are unaffected.

Also introduce tryOpenFile, which rejects directories that os.Open would happily open, so a directory matching a candidate path no longer wins the search and then fails when its lines are read.

This is the first PR of 4 to address the #1009

Profiles from Go programs refer to standard library sources under the
GOROOT of the build machine, which breaks the source and weblist views
when that path does not exist locally (e.g. a profile from another
machine), or when the program was built with -trimpath and the files
are recorded relative to $GOROOT/src.

Teach openSourceFile to fall back to the local $GOROOT/src after the
regular search fails: relative paths resolve against it directly, and
absolute paths resolve by matching the components after a /src/ one. The
fallback only runs when the existing lookup finds nothing, so previously
resolved files are unaffected.

Also introduce tryOpenFile, which rejects directories that os.Open would
happily open, so a directory matching a candidate path no longer wins
the search and then fails when its lines are read.

Co-authored-by: Aliaksandr Valialkin <valyala@victoriametrics.com>
@google-cla

google-cla Bot commented Jul 20, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

Comment thread internal/report/source.go
parent := filepath.Dir(dir)
if parent == dir {
break
if f, err := tryOpenFile(path); err == nil {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All this changes are round allowing to fallback later to other "handlers", for now we are adding the goroot handler, but in other PRs we will add more special handlers like gomodcache or vendor.

Comment thread internal/report/source.go

// tryOpenFile opens the file at filename if it exists and is not a directory,
// which os.Open would also happily open.
func tryOpenFile(filename string) (*os.File, error) {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fail fast when you try to open a directory.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you see cases where this practically happens? Asking because it seems unlikely that a source file path matches a directory name because source file names usually have an extension and directory names do not.

Comment thread internal/report/source.go
// component against gorootSrc. Binaries built with -trimpath record them
// relative to $GOROOT/src (e.g. runtime/proc.go), so resolve relative paths
// against gorootSrc directly.
func openGorootSourceFile(path, gorootSrc string) (*os.File, error) {

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the special handling for goroot, only executed if the openSourceFile previous machinery doesn't find anything.

@aalexand

aalexand commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

Please sign the CLA.

Comment thread internal/report/source.go
// reports the GOROOT this binary was built with, which is the Go installation
// used to `go install` pprof in the common case.
var gorootSrc = func() string {
if goroot := runtime.GOROOT(); goroot != "" {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think pprof binary's runtime.GOROOT() can be different from the goroot of the profiled binary? Not sure we can guarantee that this is the right default.

Comment thread internal/report/source.go

// tryOpenFile opens the file at filename if it exists and is not a directory,
// which os.Open would also happily open.
func tryOpenFile(filename string) (*os.File, error) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you see cases where this practically happens? Asking because it seems unlikely that a source file path matches a directory name because source file names usually have an extension and directory names do not.

Comment thread internal/report/source.go
if f, err := tryOpenFile(filename); err == nil {
return f, nil
}
parent := filepath.Dir(dir)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: This is historical but I think we should remove using even parent path of the search paths. When I specify /foo/bar as the search path, I do not expect that the tool will attempt /foo/src/baz.cc paths or something like that. In particular, /foo/src can be a slow NFS / remote mounted directory and trying to look up those paths will slow down the scan.

Comment thread internal/report/source.go

// openGorootSourceFile tries to open a Go standard library source file under
// gorootSrc. Binaries built without -trimpath record standard library files
// under the build machine's GOROOT (e.g. /usr/local/go/src/runtime/proc.go),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a possibility we could instead 1) modify trimPath() below to trim the absolute path prefix; 2) add $GOROOT/src to the default search path? I assume that would be enough to locate the runtime files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants