Skip to content

cmd/compile: yet another incorrect recover behavior due to defer a method wrapper #73920

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

Open
cherrymui opened this issue May 29, 2025 · 3 comments
Labels
BugReport Issues describing a possible bug in the Go implementation. compiler/runtime Issues related to the Go compiler and/or runtime. NeedsFix The path to resolution is known, but the work has not been done.
Milestone

Comments

@cherrymui
Copy link
Member

cherrymui commented May 29, 2025

Go version

Go 1.20 - Go 1.24

Output of go env in your module/workspace:

darwin/arm64 (or any)

What did you do?

https://go.dev/play/p/D621WgLz6y2

package main

func callRecover() {
	if recover() != nil {
		println("recovered")
	}
}

type T int

func (*T) M() { callRecover() }

type S struct{ *T } // has a wrapper (*S).M wrapping (*T.M)

var p = &S{new(T)}

var fn = (*S).M // using a function pointer to force using the wrapper

func main() {
	defer fn(p)
	panic("XXX")
}

What did you see happen?

The panic is recovered. The program prints "recovered" and exits normally.

What did you expect to see?

Similar to #73917, it is expected to not recover.

This is pretty much the same as #73917, except that it defers a method call with a pointer receiver, whereas it is a value receiver in #73917. I'm filing a separate issue as

  • it started to fail from a different commit,
  • this actually passes on tip, but fails with Go 1.24.

Similarly, it panics as expected if inlining is disabled.

$ go run -gcflags=-l x3.go
panic: XXX

goroutine 1 [running]:
main.main()
	/tmp/x3.go:21 +0x68
exit status 2

Go 1.19 got it right. Go 1.18 and later fail. Bisection points to CL https://go.dev/cl/422235 , which apparently has a lot of effects (I could bisect further with GOEXPERIMENT=unified, but I'll defer it for later). Before that CL, the wrapper (*S).M does a tail call to (*T).M with no inlining. After that CL, the wrapper (*S).M inlines (*T).M, while keeping the WRAPPER attribute. Similar to #73916 and #73917, this causes the panic to be treated one frame too deep.

It's been the same behavior up to Go 1.24. On tip, it changes, since CL https://go.dev/cl/650455 . Before that CL, tail call is not used for that type of wrappers, because the wrapped function (*T).M is inlineable (and actually being inlined). After that CL, we start with emitting an OTAILCALL without the WRAPPER attribute, and later inlines the wrapped function into it, still without the WRAPPER attribute. This corrects the panic stack depth issue (while leaving the issue of the wrapper not being omitted from traceback #73747).

The proposed fix for #73747, CL 675916 (as of PS 1), sets the WRAPPER attribute, which would reintroduce this bug.

@gopherbot gopherbot added the compiler/runtime Issues related to the Go compiler and/or runtime. label May 29, 2025
@gabyhelp gabyhelp added the BugReport Issues describing a possible bug in the Go implementation. label May 29, 2025
@mknyszek mknyszek added the NeedsFix The path to resolution is known, but the work has not been done. label May 30, 2025
@mknyszek mknyszek added this to the Backlog milestone May 30, 2025
@zigo101
Copy link

zigo101 commented May 30, 2025

Go 1.18 and later fail.

typo? It should be 1.20.

@gopherbot
Copy link
Contributor

Change https://go.dev/cl/677675 mentions this issue: cmd/compile: Modify inline tree to avoid parent node for tail call site.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
BugReport Issues describing a possible bug in the Go implementation. compiler/runtime Issues related to the Go compiler and/or runtime. NeedsFix The path to resolution is known, but the work has not been done.
Projects
None yet
Development

No branches or pull requests

5 participants