| // run | 
 |  | 
 | // Copyright 2010 The Go Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style | 
 | // license that can be found in the LICENSE file. | 
 |  | 
 | // Test of basic recover functionality. | 
 |  | 
 | package main | 
 |  | 
 | import ( | 
 | 	"os" | 
 | 	"reflect" | 
 | 	"runtime" | 
 | ) | 
 |  | 
 | func main() { | 
 | 	// go.tools/ssa/interp still has: | 
 | 	// - some lesser bugs in recover() | 
 | 	// - incomplete support for reflection | 
 | 	interp := os.Getenv("GOSSAINTERP") != "" | 
 |  | 
 | 	test1() | 
 | 	test1WithClosures() | 
 | 	test2() | 
 | 	test3() | 
 | 	if !interp { | 
 | 		test4() | 
 | 	} | 
 | 	test5() | 
 | 	test6() | 
 | 	test6WithClosures() | 
 | 	test7() | 
 | 	test8() | 
 | 	test9() | 
 | 	if !interp { | 
 | 		test9reflect1() | 
 | 		test9reflect2() | 
 | 	} | 
 | 	test10() | 
 | 	if !interp { | 
 | 		test10reflect1() | 
 | 		test10reflect2() | 
 | 	} | 
 | 	test11() | 
 | 	if !interp { | 
 | 		test11reflect1() | 
 | 		test11reflect2() | 
 | 	} | 
 | 	test111() | 
 | 	test12() | 
 | 	if !interp { | 
 | 		test12reflect1() | 
 | 		test12reflect2() | 
 | 	} | 
 | 	test13() | 
 | 	if !interp { | 
 | 		test13reflect1() | 
 | 		test13reflect2() | 
 | 	} | 
 | 	test14() | 
 | 	if !interp { | 
 | 		test14reflect1() | 
 | 		test14reflect2() | 
 | 		test15() | 
 | 		test16() | 
 | 	} | 
 | } | 
 |  | 
 | func die() { | 
 | 	runtime.Breakpoint() // can't depend on panic | 
 | } | 
 |  | 
 | func mustRecoverBody(v1, v2, v3, x interface{}) { | 
 | 	v := v1 | 
 | 	if v != nil { | 
 | 		println("spurious recover", v) | 
 | 		die() | 
 | 	} | 
 | 	v = v2 | 
 | 	if v == nil { | 
 | 		println("missing recover", x.(int)) | 
 | 		die() // panic is useless here | 
 | 	} | 
 | 	if v != x { | 
 | 		println("wrong value", v, x) | 
 | 		die() | 
 | 	} | 
 |  | 
 | 	// the value should be gone now regardless | 
 | 	v = v3 | 
 | 	if v != nil { | 
 | 		println("recover didn't recover") | 
 | 		die() | 
 | 	} | 
 | } | 
 |  | 
 | func doubleRecover() interface{} { | 
 | 	return recover() | 
 | } | 
 |  | 
 | func mustRecover(x interface{}) { | 
 | 	mustRecoverBody(doubleRecover(), recover(), recover(), x) | 
 | } | 
 |  | 
 | func mustNotRecover() { | 
 | 	v := recover() | 
 | 	if v != nil { | 
 | 		println("spurious recover", v) | 
 | 		die() | 
 | 	} | 
 | } | 
 |  | 
 | 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 withoutRecoverRecursive(0) // ditto | 
 | 	panic(1) | 
 | } | 
 |  | 
 | // Repeat test1 with closures instead of standard function. | 
 | // Interesting because recover bases its decision | 
 | // on the frame pointer of its caller, and a closure's | 
 | // frame pointer is in the middle of its actual arguments | 
 | // (after the hidden ones for the closed-over variables). | 
 | func test1WithClosures() { | 
 | 	defer func() { | 
 | 		v := recover() | 
 | 		if v != nil { | 
 | 			println("spurious recover in closure") | 
 | 			die() | 
 | 		} | 
 | 	}() | 
 | 	defer func(x interface{}) { | 
 | 		mustNotRecover() | 
 | 		v := recover() | 
 | 		if v == nil { | 
 | 			println("missing recover", x.(int)) | 
 | 			die() | 
 | 		} | 
 | 		if v != x { | 
 | 			println("wrong value", v, x) | 
 | 			die() | 
 | 		} | 
 | 	}(1) | 
 | 	defer func() { | 
 | 		mustNotRecover() | 
 | 	}() | 
 | 	panic(1) | 
 | } | 
 |  | 
 | func test2() { | 
 | 	// Recover only sees the panic argument | 
 | 	// if it is called from a deferred call. | 
 | 	// It does not see the panic when called from a call within a deferred call (too late) | 
 | 	// nor does it see the panic when it *is* the deferred call (too early). | 
 | 	defer mustRecover(2) | 
 | 	defer recover() // should be no-op | 
 | 	panic(2) | 
 | } | 
 |  | 
 | func test3() { | 
 | 	defer mustNotRecover() | 
 | 	defer func() { | 
 | 		recover() // should squelch | 
 | 	}() | 
 | 	panic(3) | 
 | } | 
 |  | 
 | func test4() { | 
 | 	// Equivalent to test3 but using defer to make the call. | 
 | 	defer mustNotRecover() | 
 | 	defer func() { | 
 | 		defer recover() // should squelch | 
 | 	}() | 
 | 	panic(4) | 
 | } | 
 |  | 
 | // Check that closures can set output arguments. | 
 | // Run g().  If it panics, return x; else return deflt. | 
 | func try(g func(), deflt interface{}) (x interface{}) { | 
 | 	defer func() { | 
 | 		if v := recover(); v != nil { | 
 | 			x = v | 
 | 		} | 
 | 	}() | 
 | 	defer g() | 
 | 	return deflt | 
 | } | 
 |  | 
 | // Check that closures can set output arguments. | 
 | // Run g().  If it panics, return x; else return deflt. | 
 | func try1(g func(), deflt interface{}) (x interface{}) { | 
 | 	defer func() { | 
 | 		if v := recover(); v != nil { | 
 | 			x = v | 
 | 		} | 
 | 	}() | 
 | 	defer g() | 
 | 	x = deflt | 
 | 	return | 
 | } | 
 |  | 
 | func test5() { | 
 | 	v := try(func() { panic(5) }, 55).(int) | 
 | 	if v != 5 { | 
 | 		println("wrong value", v, 5) | 
 | 		die() | 
 | 	} | 
 |  | 
 | 	s := try(func() {}, "hi").(string) | 
 | 	if s != "hi" { | 
 | 		println("wrong value", s, "hi") | 
 | 		die() | 
 | 	} | 
 |  | 
 | 	v = try1(func() { panic(5) }, 55).(int) | 
 | 	if v != 5 { | 
 | 		println("try1 wrong value", v, 5) | 
 | 		die() | 
 | 	} | 
 |  | 
 | 	s = try1(func() {}, "hi").(string) | 
 | 	if s != "hi" { | 
 | 		println("try1 wrong value", s, "hi") | 
 | 		die() | 
 | 	} | 
 | } | 
 |  | 
 | // When a deferred big call starts, it must first | 
 | // create yet another stack segment to hold the | 
 | // giant frame for x.  Make sure that doesn't | 
 | // confuse recover. | 
 | func big(mustRecover bool) { | 
 | 	var x [100000]int | 
 | 	x[0] = 1 | 
 | 	x[99999] = 1 | 
 | 	_ = x | 
 |  | 
 | 	v := recover() | 
 | 	if mustRecover { | 
 | 		if v == nil { | 
 | 			println("missing big recover") | 
 | 			die() | 
 | 		} | 
 | 	} else { | 
 | 		if v != nil { | 
 | 			println("spurious big recover") | 
 | 			die() | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | func test6() { | 
 | 	defer big(false) | 
 | 	defer big(true) | 
 | 	panic(6) | 
 | } | 
 |  | 
 | func test6WithClosures() { | 
 | 	defer func() { | 
 | 		var x [100000]int | 
 | 		x[0] = 1 | 
 | 		x[99999] = 1 | 
 | 		_ = x | 
 | 		if recover() != nil { | 
 | 			println("spurious big closure recover") | 
 | 			die() | 
 | 		} | 
 | 	}() | 
 | 	defer func() { | 
 | 		var x [100000]int | 
 | 		x[0] = 1 | 
 | 		x[99999] = 1 | 
 | 		_ = x | 
 | 		if recover() == nil { | 
 | 			println("missing big closure recover") | 
 | 			die() | 
 | 		} | 
 | 	}() | 
 | 	panic("6WithClosures") | 
 | } | 
 |  | 
 | func test7() { | 
 | 	ok := false | 
 | 	func() { | 
 | 		// should panic, then call mustRecover 7, which stops the panic. | 
 | 		// then should keep processing ordinary defers earlier than that one | 
 | 		// before returning. | 
 | 		// this test checks that the defer func on the next line actually runs. | 
 | 		defer func() { ok = true }() | 
 | 		defer mustRecover(7) | 
 | 		panic(7) | 
 | 	}() | 
 | 	if !ok { | 
 | 		println("did not run ok func") | 
 | 		die() | 
 | 	} | 
 | } | 
 |  | 
 | func varargs(s *int, a ...int) { | 
 | 	*s = 0 | 
 | 	for _, v := range a { | 
 | 		*s += v | 
 | 	} | 
 | 	if recover() != nil { | 
 | 		*s += 100 | 
 | 	} | 
 | } | 
 |  | 
 | func test8a() (r int) { | 
 | 	defer varargs(&r, 1, 2, 3) | 
 | 	panic(0) | 
 | } | 
 |  | 
 | func test8b() (r int) { | 
 | 	defer varargs(&r, 4, 5, 6) | 
 | 	return | 
 | } | 
 |  | 
 | func test8() { | 
 | 	if test8a() != 106 || test8b() != 15 { | 
 | 		println("wrong value") | 
 | 		die() | 
 | 	} | 
 | } | 
 |  | 
 | type I interface { | 
 | 	M() | 
 | } | 
 |  | 
 | // pointer receiver, so no wrapper in i.M() | 
 | type T1 struct{} | 
 |  | 
 | func (*T1) M() { | 
 | 	mustRecoverBody(doubleRecover(), recover(), recover(), 9) | 
 | } | 
 |  | 
 | func test9() { | 
 | 	var i I = &T1{} | 
 | 	defer i.M() | 
 | 	panic(9) | 
 | } | 
 |  | 
 | func test9reflect1() { | 
 | 	f := reflect.ValueOf(&T1{}).Method(0).Interface().(func()) | 
 | 	defer f() | 
 | 	panic(9) | 
 | } | 
 |  | 
 | func test9reflect2() { | 
 | 	f := reflect.TypeOf(&T1{}).Method(0).Func.Interface().(func(*T1)) | 
 | 	defer f(&T1{}) | 
 | 	panic(9) | 
 | } | 
 |  | 
 | // word-sized value receiver, so no wrapper in i.M() | 
 | type T2 uintptr | 
 |  | 
 | func (T2) M() { | 
 | 	mustRecoverBody(doubleRecover(), recover(), recover(), 10) | 
 | } | 
 |  | 
 | func test10() { | 
 | 	var i I = T2(0) | 
 | 	defer i.M() | 
 | 	panic(10) | 
 | } | 
 |  | 
 | func test10reflect1() { | 
 | 	f := reflect.ValueOf(T2(0)).Method(0).Interface().(func()) | 
 | 	defer f() | 
 | 	panic(10) | 
 | } | 
 |  | 
 | func test10reflect2() { | 
 | 	f := reflect.TypeOf(T2(0)).Method(0).Func.Interface().(func(T2)) | 
 | 	defer f(T2(0)) | 
 | 	panic(10) | 
 | } | 
 |  | 
 | // tiny receiver, so basic wrapper in i.M() | 
 | type T3 struct{} | 
 |  | 
 | func (T3) M() { | 
 | 	mustRecoverBody(doubleRecover(), recover(), recover(), 11) | 
 | } | 
 |  | 
 | func test11() { | 
 | 	var i I = T3{} | 
 | 	defer i.M() | 
 | 	panic(11) | 
 | } | 
 |  | 
 | func test11reflect1() { | 
 | 	f := reflect.ValueOf(T3{}).Method(0).Interface().(func()) | 
 | 	defer f() | 
 | 	panic(11) | 
 | } | 
 |  | 
 | func test11reflect2() { | 
 | 	f := reflect.TypeOf(T3{}).Method(0).Func.Interface().(func(T3)) | 
 | 	defer f(T3{}) | 
 | 	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 | 
 |  | 
 | func (T4) M() { | 
 | 	mustRecoverBody(doubleRecover(), recover(), recover(), 12) | 
 | } | 
 |  | 
 | func test12() { | 
 | 	var i I = T4{} | 
 | 	defer i.M() | 
 | 	panic(12) | 
 | } | 
 |  | 
 | func test12reflect1() { | 
 | 	f := reflect.ValueOf(T4{}).Method(0).Interface().(func()) | 
 | 	defer f() | 
 | 	panic(12) | 
 | } | 
 |  | 
 | func test12reflect2() { | 
 | 	f := reflect.TypeOf(T4{}).Method(0).Func.Interface().(func(T4)) | 
 | 	defer f(T4{}) | 
 | 	panic(12) | 
 | } | 
 |  | 
 | // enormous receiver, so wrapper splits stack to call M | 
 | type T5 [8192]byte | 
 |  | 
 | func (T5) M() { | 
 | 	mustRecoverBody(doubleRecover(), recover(), recover(), 13) | 
 | } | 
 |  | 
 | func test13() { | 
 | 	var i I = T5{} | 
 | 	defer i.M() | 
 | 	panic(13) | 
 | } | 
 |  | 
 | func test13reflect1() { | 
 | 	f := reflect.ValueOf(T5{}).Method(0).Interface().(func()) | 
 | 	defer f() | 
 | 	panic(13) | 
 | } | 
 |  | 
 | func test13reflect2() { | 
 | 	f := reflect.TypeOf(T5{}).Method(0).Func.Interface().(func(T5)) | 
 | 	defer f(T5{}) | 
 | 	panic(13) | 
 | } | 
 |  | 
 | // enormous receiver + enormous method frame, so wrapper splits stack to call M, | 
 | // and then M splits stack to allocate its frame. | 
 | // recover must look back two frames to find the panic. | 
 | type T6 [8192]byte | 
 |  | 
 | var global byte | 
 |  | 
 | func (T6) M() { | 
 | 	var x [8192]byte | 
 | 	x[0] = 1 | 
 | 	x[1] = 2 | 
 | 	for i := range x { | 
 | 		global += x[i] | 
 | 	} | 
 | 	mustRecoverBody(doubleRecover(), recover(), recover(), 14) | 
 | } | 
 |  | 
 | func test14() { | 
 | 	var i I = T6{} | 
 | 	defer i.M() | 
 | 	panic(14) | 
 | } | 
 |  | 
 | func test14reflect1() { | 
 | 	f := reflect.ValueOf(T6{}).Method(0).Interface().(func()) | 
 | 	defer f() | 
 | 	panic(14) | 
 | } | 
 |  | 
 | func test14reflect2() { | 
 | 	f := reflect.TypeOf(T6{}).Method(0).Func.Interface().(func(T6)) | 
 | 	defer f(T6{}) | 
 | 	panic(14) | 
 | } | 
 |  | 
 | // function created by reflect.MakeFunc | 
 |  | 
 | func reflectFunc(args []reflect.Value) (results []reflect.Value) { | 
 | 	mustRecoverBody(doubleRecover(), recover(), recover(), 15) | 
 | 	return nil | 
 | } | 
 |  | 
 | func test15() { | 
 | 	f := reflect.MakeFunc(reflect.TypeOf((func())(nil)), reflectFunc).Interface().(func()) | 
 | 	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) | 
 | } |