summaryrefslogtreecommitdiff
path: root/test/recover.go
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-09-06 13:19:08 -0400
committerRuss Cox <rsc@golang.org>2014-09-06 13:19:08 -0400
commit3c63238a55767eb0329761b3538362b67f66291e (patch)
tree5fc3426c74bfcc9a30d46c38d3f68afe37cc0679 /test/recover.go
parent38481ac10bb2aff82282b12a26d989e70ca7b375 (diff)
downloadgo-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.go48
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