Skip to content

cmd/compile: incorrect recover behavior due to defer a method wrapper #73917

Open
@cherrymui

Description

@cherrymui

Go version

tip, and Go 1.18 - 1.24

Output of go env in your module/workspace:

darwin/arm64 (or any)

What did you do?

Run https://go.dev/play/p/z4BHWcNalVg

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 #73916, it is expected to not recover.

Also similarly, it panics as expected if inlining is disabled.

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

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

Go 1.17 got it right. Go 1.18 and later fail. Bisection points to CL https://go.dev/cl/327871 . Also similarly, it is a phase ordering change. Before that CL, the wrapper S.M is generated late and cannot inline the wrapped function (*T).M. After the CL, it does, while keeping the WRAPPER attribute. The rest of the reasoning is the same as #73916.

Found while investigating #73747.

Metadata

Metadata

Assignees

Labels

BugReportIssues describing a possible bug in the Go implementation.compiler/runtimeIssues related to the Go compiler and/or runtime.

Type

No type

Projects

Status

Todo

Relationships

None yet

Development

No branches or pull requests

Issue actions