Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/compile: encoded pkg path shown in stack trace #35558

Open
myitcv opened this issue Nov 13, 2019 · 8 comments
Open

cmd/compile: encoded pkg path shown in stack trace #35558

myitcv opened this issue Nov 13, 2019 · 8 comments
Labels
NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@myitcv
Copy link
Member

myitcv commented Nov 13, 2019

What version of Go are you using (go version)?

$ go version
go version devel +99957b6930 Tue Nov 12 05:35:33 2019 +0000 linux/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="/home/myitcv/.cache/go-build"
GOENV="/home/myitcv/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/myitcv/gostuff"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/home/myitcv/gos"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/home/myitcv/gos/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build670035236=/tmp/go-build -gno-record-gcc-switches"

What did you do?

Run the following testscript repro:

go run main.go

-- go.mod --
module mod.com

go 1.14

require (
        golang.org/x/net v0.0.0-20190620200207-3b0461eec859 // indirect
        gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637
)
-- main.go --
package main

import "gopkg.in/tomb.v2"

func main() {
	done := make(chan struct{})
	var t tomb.Tomb
	t.Go(func() error {
		panic("here")
		close(done)
		return nil
	})
	<-done
}

What did you expect to see?

panic: here

goroutine 18 [running]:
main.main.func1(0x0, 0x0)
        /home/myitcv/gostuff/src/github.com/myitcv/playground/main.go:9 +0x39
gopkg.in/tomb.v2.(*Tomb).run(0xc00018e000, 0xc00018a060)
        /home/myitcv/gostuff/pkg/mod/gopkg.in/tomb.v2@v2.0.0-20161208151619-d5d1b5820637/tomb.go:163 +0x38
created by gopkg.in/tomb.v2.(*Tomb).Go
        /home/myitcv/gostuff/pkg/mod/gopkg.in/tomb.v2@v2.0.0-20161208151619-d5d1b5820637/tomb.go:159 +0xba
exit status 2

What did you see instead?

panic: here

goroutine 18 [running]:
main.main.func1(0x0, 0x0)
        /home/myitcv/gostuff/src/github.com/myitcv/playground/main.go:9 +0x39
gopkg.in/tomb%2ev2.(*Tomb).run(0xc00018e000, 0xc00018a060)
        /home/myitcv/gostuff/pkg/mod/gopkg.in/tomb.v2@v2.0.0-20161208151619-d5d1b5820637/tomb.go:163 +0x38
created by gopkg.in/tomb%2ev2.(*Tomb).Go
        /home/myitcv/gostuff/pkg/mod/gopkg.in/tomb.v2@v2.0.0-20161208151619-d5d1b5820637/tomb.go:159 +0xba
exit status 2

Note the %2e in the stack trace.

cc @bcmills @randall77 @jayconrod

@jayconrod jayconrod added GoCommand cmd/go modules NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. labels Nov 13, 2019
@jayconrod jayconrod added this to the Go1.14 milestone Nov 13, 2019
@jayconrod jayconrod self-assigned this Nov 14, 2019
@jayconrod jayconrod changed the title cmd/go: encoded pkg path shown in stack trace cmd/compile: encoded pkg path shown in stack trace Nov 14, 2019
@jayconrod jayconrod modified the milestones: Go1.14, Backlog Nov 14, 2019
@jayconrod jayconrod removed their assignment Nov 14, 2019
@jayconrod
Copy link
Contributor

It seems like the compiler is doing this. I was able to reproduce this back as far as 1.11.

Here's a simpler test case that shows %2e in the symbol table. Versions before 1.13 have %22%22 instead ("").

go tool compile -o foo.a -p example.com/foo.v2 foo.go
go tool nm foo.a
! stdout %2e

-- foo.go --
package main

func main() {}

@cherrymui @randall77 @aclements Is this a bug or intended behavior?

@cherrymui
Copy link
Member

Yeah, this is just the symbol name in the binary. The symbol names are escaped to avoid collisions as well as other problems. We never document or guarantee how the symbol names are constructed, although we try to make it readable and close to the identifier in the source code. Gccgo constructs symbol names differently.

Is this a bug or intended behavior?

I would say this is an implementation detail that happens to be this way.

Versions before 1.13 have %22%22 instead ("").

Yeah. Before 1.13 the compiler writes "" and the linker expands to the same escaped name.

@jayconrod
Copy link
Contributor

@cherrymui Escaping symbol names in compiled code makes sense to me, but can we unescape those names in stack traces?

@ianlancetaylor
Copy link
Contributor

We could tweak the names in stack traces, but the question is: which choice is more confusing? For example, do people expect to be able to match the symbol names shown in stack traces to the symbol names reported by nm?

@aclements
Copy link
Member

I suspect very few people are running nm, while a lot of people are looking at stack traces. OTOH, the sorts of things that cause escaping aren't very common. I'd lean toward showing un-escaped function names in the stack trace.

@ianlancetaylor
Copy link
Contributor

It's exactly because few people run nm that I think this kind of thing can be problematic. Just as you're running into some problem that requires you to reach for the uncommon tool, you encounter the baffling fact that the symbol you see in the stack trace is not in the binary, at which point you face hours of debugging until you discover the truth. If you used nm all the time you would know about this problem.

@aclements
Copy link
Member

Hmm. That assumes the user's mental model is that the stack trace contains binary symbols, as opposed to something at the level of language semantics like package paths and function/method names. This makes perfect sense to us as compiler authors, but I doubt many users think of it this way. Indeed, we go to some trouble to make the stack traces match language semantics rather than implementation details: eliding wrapper functions, rewriting names of some runtime functions, etc. All of our binary symbols on Darwin start with an underscore, but we don't print that in the stack trace. go doc gopkg.in/tomb.v2 works, but go doc gopkg.in/tomb%2ev2 doesn't. These are all operating at the language level.

That said, our symbols are so lightly escaped right now that we can just have our cake and eat it, too, and only occasionally find a bit of egg shell. We might as well err on the side of printing the symbol name since that will confuse basically no one (though it may surprise, as demonstrated by this bug report!) and will help the few people for whom it is better to have the raw symbol name.

I do wonder if generics will change this, if we use a stenciling implementation. If our symbols become significantly more mangled (say, like C++ symbols, though hopefully not that bad), I absolutely think it would be more meaningful to show something semantic in a stack trace over a mangled symbol name.

@rsc
Copy link
Contributor

rsc commented Jan 6, 2021

The rule here (only escape dots after the final slash in the package path) was chosen deliberately as something that would only very rarely arise. You can make up examples like creating github.com/rsc/p (a repo) containing directories q and q.r, where q defines type r with value method m and q.r defines function m. Then "github.com/rsc/p/q.r.m" is ambiguous, and the root cause is you can't identify which dot is the package-dot-name dot.

Unescaping the stack trace would make it ambiguous, but I think that's probably the right thing to do. The %2e is not something users understand how to read. Fixing the stack traces would probably imply changing the result of runtime.Func.Name to return an unescaped string (meaning we'd just store the unescaped one in the func table in the binary to begin with). On the other hand, the case is by design rare - it basically only affects gopkg.in.

Waiting to see what happens with generics seems like a good idea. It may be that we decide Func.Name should return ambiguous names, because you don't want to see all the detail about specific type parameters in the stack traces.
For example it may be that we want to see just "math.Min(...)" and not "math.Min(float64)(...)". That one is short but others will be much longer. If we embrace the ambiguity in that case then removing the %2e becomes even more of a a no-brainer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

6 participants