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.
Comment From: gabyhelp
Related Issues
- cmd/compile: incorrect recover behavior due to defer wrapper #73916
- cmd/compile: mid-stack inlining in a method wrapper can cause recover to fail #23557 (closed)
- cmd/compile: "Open defer" of method call miscompiled at tip #45062 (closed)
- affected/package: builtin Inlining causes spec violation in recover() #54119 (closed)
- builtin: can't "defer recover()" without an anonymous func #20768 (closed)
- `defer recover()` does not recover from panic #53169 (closed)
- Documentation: deferring a recover directly is a no-op (spec) #25815 (closed)
- cmd/compile (or runtime): deferred calls are missed under certain situations #48898 (closed)
Related Code Changes
- cmd/compile: don't inline functions that call recover
- cmd/compile: be sure to wrap defer/go calls with arguments
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
Comment From: gopherbot
Change https://go.dev/cl/677675 mentions this issue: cmd/compile: Modify inline tree to avoid parent node for tail call site.
Comment From: gopherbot
Change https://go.dev/cl/685375 mentions this issue: runtime: iterate through inlinings when processing recover()