mirror of
https://github.com/golang/go
synced 2025-05-04 03:11:34 +00:00
runtime: fix panic/wrapper/recover math
The gp->panicwrap adjustment is just fatally flawed. Now that there is a Panic.argp field, update that instead. That can be done on entry only, so that unwinding doesn't need to worry about undoing anything. The wrappers emit a few more instructions in the prologue but everything else in the system gets much simpler. It also fixes (without trying) a broken test I never checked in. Fixes #7491. LGTM=khr R=khr CC=dvyukov, golang-codereviews, iant, r https://golang.org/cl/135490044
This commit is contained in:
@ -47,6 +47,7 @@ func main() {
|
||||
test11reflect1()
|
||||
test11reflect2()
|
||||
}
|
||||
test111()
|
||||
test12()
|
||||
if !interp {
|
||||
test12reflect1()
|
||||
@ -77,7 +78,7 @@ func mustRecoverBody(v1, v2, v3, x interface{}) {
|
||||
}
|
||||
v = v2
|
||||
if v == nil {
|
||||
println("missing recover")
|
||||
println("missing recover", x.(int))
|
||||
die() // panic is useless here
|
||||
}
|
||||
if v != x {
|
||||
@ -137,7 +138,7 @@ func test1WithClosures() {
|
||||
mustNotRecover()
|
||||
v := recover()
|
||||
if v == nil {
|
||||
println("missing recover")
|
||||
println("missing recover", x.(int))
|
||||
die()
|
||||
}
|
||||
if v != x {
|
||||
@ -406,6 +407,49 @@ func test11reflect2() {
|
||||
panic(11)
|
||||
}
|
||||
|
||||
// tiny receiver, so basic wrapper in i.M()
|
||||
type T3deeper struct{}
|
||||
|
||||
func (T3deeper) M() {
|
||||
badstate() // difference from T3
|
||||
mustRecoverBody(doubleRecover(), recover(), recover(), 111)
|
||||
}
|
||||
|
||||
func test111() {
|
||||
var i I = T3deeper{}
|
||||
defer i.M()
|
||||
panic(111)
|
||||
}
|
||||
|
||||
type Tiny struct{}
|
||||
|
||||
func (Tiny) M() {
|
||||
panic(112)
|
||||
}
|
||||
|
||||
// i.M is a wrapper, and i.M panics.
|
||||
//
|
||||
// This is a torture test for an old implementation of recover that
|
||||
// tried to deal with wrapper functions by doing some argument
|
||||
// positioning math on both entry and exit. Doing anything on exit
|
||||
// is a problem because sometimes functions exit via panic instead
|
||||
// of an ordinary return, so panic would have to know to do the
|
||||
// same math when unwinding the stack. It gets complicated fast.
|
||||
// This particular test never worked with the old scheme, because
|
||||
// panic never did the right unwinding math.
|
||||
//
|
||||
// The new scheme adjusts Panic.argp on entry to a wrapper.
|
||||
// It has no exit work, so if a wrapper is interrupted by a panic,
|
||||
// there's no cleanup that panic itself must do.
|
||||
// This test just works now.
|
||||
func badstate() {
|
||||
defer func() {
|
||||
recover()
|
||||
}()
|
||||
var i I = Tiny{}
|
||||
i.M()
|
||||
}
|
||||
|
||||
// large receiver, so basic wrapper in i.M()
|
||||
type T4 [2]string
|
||||
|
||||
|
Reference in New Issue
Block a user