diff options
author | Russ Cox <rsc@golang.org> | 2014-09-06 13:19:08 -0400 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2014-09-06 13:19:08 -0400 |
commit | 3c63238a55767eb0329761b3538362b67f66291e (patch) | |
tree | 5fc3426c74bfcc9a30d46c38d3f68afe37cc0679 /test/recover.go | |
parent | 38481ac10bb2aff82282b12a26d989e70ca7b375 (diff) | |
download | go-3c63238a55767eb0329761b3538362b67f66291e.tar.gz |
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 issue 7491.
LGTM=khr
R=khr
CC=dvyukov, golang-codereviews, iant, r
https://codereview.appspot.com/135490044
Diffstat (limited to 'test/recover.go')
-rw-r--r-- | test/recover.go | 48 |
1 files changed, 46 insertions, 2 deletions
diff --git a/test/recover.go b/test/recover.go index 071be6667..6287d6507 100644 --- a/test/recover.go +++ b/test/recover.go @@ -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 |