Skip to content

Commit 08376e1

Browse files
committed
runtime: iterate through inlinings when processing recover()
We care about the wrapper-ness of logical frames, not physical frames. Fixes #73916 Fixes #73917 Fixex #73920 Change-Id: Ia17c8390e71e6c0e13e23dcbb7bc7273ef25da90 Reviewed-on: https://go-review.googlesource.com/c/go/+/685375 Reviewed-by: Keith Randall <[email protected]> Reviewed-by: Cuong Manh Le <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Cherry Mui <[email protected]>
1 parent c76c3ab commit 08376e1

File tree

5 files changed

+160
-11
lines changed

5 files changed

+160
-11
lines changed

src/runtime/panic.go

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1142,18 +1142,21 @@ func gorecover(_ uintptr) any {
11421142
nonWrapperFrames := 0
11431143
loop:
11441144
for ; u.valid(); u.next() {
1145-
switch u.frame.fn.funcID {
1146-
case abi.FuncIDWrapper:
1147-
continue
1148-
case abi.FuncID_gopanic:
1149-
if u.frame.fp == uintptr(p.gopanicFP) && nonWrapperFrames > 0 {
1150-
canRecover = true
1151-
}
1152-
break loop
1153-
default:
1154-
nonWrapperFrames++
1155-
if nonWrapperFrames > 1 {
1145+
for iu, f := newInlineUnwinder(u.frame.fn, u.symPC()); f.valid(); f = iu.next(f) {
1146+
sf := iu.srcFunc(f)
1147+
switch sf.funcID {
1148+
case abi.FuncIDWrapper:
1149+
continue
1150+
case abi.FuncID_gopanic:
1151+
if u.frame.fp == uintptr(p.gopanicFP) && nonWrapperFrames > 0 {
1152+
canRecover = true
1153+
}
11561154
break loop
1155+
default:
1156+
nonWrapperFrames++
1157+
if nonWrapperFrames > 1 {
1158+
break loop
1159+
}
11571160
}
11581161
}
11591162
}

test/fixedbugs/issue73916.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// run
2+
3+
// Copyright 2025 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package main
8+
9+
func callRecover() {
10+
if recover() != nil {
11+
println("recovered")
12+
}
13+
}
14+
15+
func F(int) { callRecover() }
16+
17+
func main() {
18+
mustPanic(func() {
19+
defer F(1)
20+
panic("XXX")
21+
})
22+
}
23+
24+
func mustPanic(f func()) {
25+
defer func() {
26+
r := recover()
27+
if r == nil {
28+
panic("didn't panic")
29+
}
30+
}()
31+
f()
32+
}

test/fixedbugs/issue73916b.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// run
2+
3+
// Copyright 2025 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package main
8+
9+
func callRecover() {
10+
func() {
11+
if recover() != nil {
12+
println("recovered")
13+
}
14+
}()
15+
}
16+
17+
func F() int { callRecover(); return 0 }
18+
19+
func main() {
20+
mustPanic(func() {
21+
defer F()
22+
panic("XXX")
23+
})
24+
}
25+
26+
func mustPanic(f func()) {
27+
defer func() {
28+
r := recover()
29+
if r == nil {
30+
panic("didn't panic")
31+
}
32+
}()
33+
f()
34+
}

test/fixedbugs/issue73917.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// run
2+
3+
// Copyright 2025 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package main
8+
9+
func callRecover() {
10+
if recover() != nil {
11+
println("recovered")
12+
}
13+
}
14+
15+
type T int
16+
17+
func (*T) M() { callRecover() }
18+
19+
type S struct{ *T } // has a wrapper S.M wrapping (*T.M)
20+
21+
var p = S{new(T)}
22+
23+
var fn = S.M // using a function pointer to force using the wrapper
24+
25+
func main() {
26+
mustPanic(func() {
27+
defer fn(p)
28+
panic("XXX")
29+
})
30+
}
31+
32+
func mustPanic(f func()) {
33+
defer func() {
34+
r := recover()
35+
if r == nil {
36+
panic("didn't panic")
37+
}
38+
}()
39+
f()
40+
}

test/fixedbugs/issue73920.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// run
2+
3+
// Copyright 2025 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package main
8+
9+
func callRecover() {
10+
if recover() != nil {
11+
println("recovered")
12+
}
13+
}
14+
15+
type T int
16+
17+
func (*T) M() { callRecover() }
18+
19+
type S struct{ *T } // has a wrapper (*S).M wrapping (*T.M)
20+
21+
var p = &S{new(T)}
22+
23+
var fn = (*S).M // using a function pointer to force using the wrapper
24+
25+
func main() {
26+
mustPanic(func() {
27+
defer fn(p)
28+
panic("XXX")
29+
})
30+
}
31+
32+
func mustPanic(f func()) {
33+
defer func() {
34+
r := recover()
35+
if r == nil {
36+
panic("didn't panic")
37+
}
38+
}()
39+
f()
40+
}

0 commit comments

Comments
 (0)