diff options
Diffstat (limited to 'test/recover.go')
| -rw-r--r-- | test/recover.go | 92 | 
1 files changed, 87 insertions, 5 deletions
| diff --git a/test/recover.go b/test/recover.go index 071be6667..f92c15c1d 100644 --- a/test/recover.go +++ b/test/recover.go @@ -47,6 +47,7 @@ func main() {  		test11reflect1()  		test11reflect2()  	} +	test111()  	test12()  	if !interp {  		test12reflect1() @@ -62,6 +63,7 @@ func main() {  		test14reflect1()  		test14reflect2()  		test15() +		test16()  	}  } @@ -77,7 +79,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 { @@ -113,10 +115,23 @@ func withoutRecover() {  	mustNotRecover() // because it's a sub-call  } +func withoutRecoverRecursive(n int) { +	if n == 0 { +		withoutRecoverRecursive(1) +	} else { +		v := recover() +		if v != nil { +			println("spurious recover (recursive)", v) +			die() +		} +	} +} +  func test1() { -	defer mustNotRecover() // because mustRecover will squelch it -	defer mustRecover(1)   // because of panic below -	defer withoutRecover() // should be no-op, leaving for mustRecover to find +	defer mustNotRecover()           // because mustRecover will squelch it +	defer mustRecover(1)             // because of panic below +	defer withoutRecover()           // should be no-op, leaving for mustRecover to find +	defer withoutRecoverRecursive(0) // ditto  	panic(1)  } @@ -137,7 +152,7 @@ func test1WithClosures() {  		mustNotRecover()  		v := recover()  		if v == nil { -			println("missing recover") +			println("missing recover", x.(int))  			die()  		}  		if v != x { @@ -406,6 +421,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 @@ -503,3 +561,27 @@ func test15() {  	defer f()  	panic(15)  } + +func reflectFunc2(args []reflect.Value) (results []reflect.Value) { +	// This will call reflectFunc3 +	args[0].Interface().(func())() +	return nil +} + +func reflectFunc3(args []reflect.Value) (results []reflect.Value) { +	if v := recover(); v != nil { +		println("spurious recover", v) +		die() +	} +	return nil +} + +func test16() { +	defer mustRecover(16) + +	f2 := reflect.MakeFunc(reflect.TypeOf((func(func()))(nil)), reflectFunc2).Interface().(func(func())) +	f3 := reflect.MakeFunc(reflect.TypeOf((func())(nil)), reflectFunc3).Interface().(func()) +	defer f2(f3) + +	panic(16) +} | 
