Home | History | Annotate | Download | only in test
      1 // run
      2 
      3 // Copyright 2010 The Go Authors. All rights reserved.
      4 // Use of this source code is governed by a BSD-style
      5 // license that can be found in the LICENSE file.
      6 
      7 // Test of basic recover functionality.
      8 
      9 package main
     10 
     11 import (
     12 	"os"
     13 	"reflect"
     14 	"runtime"
     15 )
     16 
     17 func main() {
     18 	// go.tools/ssa/interp still has:
     19 	// - some lesser bugs in recover()
     20 	// - incomplete support for reflection
     21 	interp := os.Getenv("GOSSAINTERP") != ""
     22 
     23 	test1()
     24 	test1WithClosures()
     25 	test2()
     26 	test3()
     27 	if !interp {
     28 		test4()
     29 	}
     30 	test5()
     31 	test6()
     32 	test6WithClosures()
     33 	test7()
     34 	test8()
     35 	test9()
     36 	if !interp {
     37 		test9reflect1()
     38 		test9reflect2()
     39 	}
     40 	test10()
     41 	if !interp {
     42 		test10reflect1()
     43 		test10reflect2()
     44 	}
     45 	test11()
     46 	if !interp {
     47 		test11reflect1()
     48 		test11reflect2()
     49 	}
     50 	test111()
     51 	test12()
     52 	if !interp {
     53 		test12reflect1()
     54 		test12reflect2()
     55 	}
     56 	test13()
     57 	if !interp {
     58 		test13reflect1()
     59 		test13reflect2()
     60 	}
     61 	test14()
     62 	if !interp {
     63 		test14reflect1()
     64 		test14reflect2()
     65 		test15()
     66 		test16()
     67 	}
     68 }
     69 
     70 func die() {
     71 	runtime.Breakpoint() // can't depend on panic
     72 }
     73 
     74 func mustRecoverBody(v1, v2, v3, x interface{}) {
     75 	v := v1
     76 	if v != nil {
     77 		println("spurious recover", v)
     78 		die()
     79 	}
     80 	v = v2
     81 	if v == nil {
     82 		println("missing recover", x.(int))
     83 		die() // panic is useless here
     84 	}
     85 	if v != x {
     86 		println("wrong value", v, x)
     87 		die()
     88 	}
     89 
     90 	// the value should be gone now regardless
     91 	v = v3
     92 	if v != nil {
     93 		println("recover didn't recover")
     94 		die()
     95 	}
     96 }
     97 
     98 func doubleRecover() interface{} {
     99 	return recover()
    100 }
    101 
    102 func mustRecover(x interface{}) {
    103 	mustRecoverBody(doubleRecover(), recover(), recover(), x)
    104 }
    105 
    106 func mustNotRecover() {
    107 	v := recover()
    108 	if v != nil {
    109 		println("spurious recover", v)
    110 		die()
    111 	}
    112 }
    113 
    114 func withoutRecover() {
    115 	mustNotRecover() // because it's a sub-call
    116 }
    117 
    118 func withoutRecoverRecursive(n int) {
    119 	if n == 0 {
    120 		withoutRecoverRecursive(1)
    121 	} else {
    122 		v := recover()
    123 		if v != nil {
    124 			println("spurious recover (recursive)", v)
    125 			die()
    126 		}
    127 	}
    128 }
    129 
    130 func test1() {
    131 	defer mustNotRecover()           // because mustRecover will squelch it
    132 	defer mustRecover(1)             // because of panic below
    133 	defer withoutRecover()           // should be no-op, leaving for mustRecover to find
    134 	defer withoutRecoverRecursive(0) // ditto
    135 	panic(1)
    136 }
    137 
    138 // Repeat test1 with closures instead of standard function.
    139 // Interesting because recover bases its decision
    140 // on the frame pointer of its caller, and a closure's
    141 // frame pointer is in the middle of its actual arguments
    142 // (after the hidden ones for the closed-over variables).
    143 func test1WithClosures() {
    144 	defer func() {
    145 		v := recover()
    146 		if v != nil {
    147 			println("spurious recover in closure")
    148 			die()
    149 		}
    150 	}()
    151 	defer func(x interface{}) {
    152 		mustNotRecover()
    153 		v := recover()
    154 		if v == nil {
    155 			println("missing recover", x.(int))
    156 			die()
    157 		}
    158 		if v != x {
    159 			println("wrong value", v, x)
    160 			die()
    161 		}
    162 	}(1)
    163 	defer func() {
    164 		mustNotRecover()
    165 	}()
    166 	panic(1)
    167 }
    168 
    169 func test2() {
    170 	// Recover only sees the panic argument
    171 	// if it is called from a deferred call.
    172 	// It does not see the panic when called from a call within a deferred call (too late)
    173 	// nor does it see the panic when it *is* the deferred call (too early).
    174 	defer mustRecover(2)
    175 	defer recover() // should be no-op
    176 	panic(2)
    177 }
    178 
    179 func test3() {
    180 	defer mustNotRecover()
    181 	defer func() {
    182 		recover() // should squelch
    183 	}()
    184 	panic(3)
    185 }
    186 
    187 func test4() {
    188 	// Equivalent to test3 but using defer to make the call.
    189 	defer mustNotRecover()
    190 	defer func() {
    191 		defer recover() // should squelch
    192 	}()
    193 	panic(4)
    194 }
    195 
    196 // Check that closures can set output arguments.
    197 // Run g().  If it panics, return x; else return deflt.
    198 func try(g func(), deflt interface{}) (x interface{}) {
    199 	defer func() {
    200 		if v := recover(); v != nil {
    201 			x = v
    202 		}
    203 	}()
    204 	defer g()
    205 	return deflt
    206 }
    207 
    208 // Check that closures can set output arguments.
    209 // Run g().  If it panics, return x; else return deflt.
    210 func try1(g func(), deflt interface{}) (x interface{}) {
    211 	defer func() {
    212 		if v := recover(); v != nil {
    213 			x = v
    214 		}
    215 	}()
    216 	defer g()
    217 	x = deflt
    218 	return
    219 }
    220 
    221 func test5() {
    222 	v := try(func() { panic(5) }, 55).(int)
    223 	if v != 5 {
    224 		println("wrong value", v, 5)
    225 		die()
    226 	}
    227 
    228 	s := try(func() {}, "hi").(string)
    229 	if s != "hi" {
    230 		println("wrong value", s, "hi")
    231 		die()
    232 	}
    233 
    234 	v = try1(func() { panic(5) }, 55).(int)
    235 	if v != 5 {
    236 		println("try1 wrong value", v, 5)
    237 		die()
    238 	}
    239 
    240 	s = try1(func() {}, "hi").(string)
    241 	if s != "hi" {
    242 		println("try1 wrong value", s, "hi")
    243 		die()
    244 	}
    245 }
    246 
    247 // When a deferred big call starts, it must first
    248 // create yet another stack segment to hold the
    249 // giant frame for x.  Make sure that doesn't
    250 // confuse recover.
    251 func big(mustRecover bool) {
    252 	var x [100000]int
    253 	x[0] = 1
    254 	x[99999] = 1
    255 	_ = x
    256 
    257 	v := recover()
    258 	if mustRecover {
    259 		if v == nil {
    260 			println("missing big recover")
    261 			die()
    262 		}
    263 	} else {
    264 		if v != nil {
    265 			println("spurious big recover")
    266 			die()
    267 		}
    268 	}
    269 }
    270 
    271 func test6() {
    272 	defer big(false)
    273 	defer big(true)
    274 	panic(6)
    275 }
    276 
    277 func test6WithClosures() {
    278 	defer func() {
    279 		var x [100000]int
    280 		x[0] = 1
    281 		x[99999] = 1
    282 		_ = x
    283 		if recover() != nil {
    284 			println("spurious big closure recover")
    285 			die()
    286 		}
    287 	}()
    288 	defer func() {
    289 		var x [100000]int
    290 		x[0] = 1
    291 		x[99999] = 1
    292 		_ = x
    293 		if recover() == nil {
    294 			println("missing big closure recover")
    295 			die()
    296 		}
    297 	}()
    298 	panic("6WithClosures")
    299 }
    300 
    301 func test7() {
    302 	ok := false
    303 	func() {
    304 		// should panic, then call mustRecover 7, which stops the panic.
    305 		// then should keep processing ordinary defers earlier than that one
    306 		// before returning.
    307 		// this test checks that the defer func on the next line actually runs.
    308 		defer func() { ok = true }()
    309 		defer mustRecover(7)
    310 		panic(7)
    311 	}()
    312 	if !ok {
    313 		println("did not run ok func")
    314 		die()
    315 	}
    316 }
    317 
    318 func varargs(s *int, a ...int) {
    319 	*s = 0
    320 	for _, v := range a {
    321 		*s += v
    322 	}
    323 	if recover() != nil {
    324 		*s += 100
    325 	}
    326 }
    327 
    328 func test8a() (r int) {
    329 	defer varargs(&r, 1, 2, 3)
    330 	panic(0)
    331 }
    332 
    333 func test8b() (r int) {
    334 	defer varargs(&r, 4, 5, 6)
    335 	return
    336 }
    337 
    338 func test8() {
    339 	if test8a() != 106 || test8b() != 15 {
    340 		println("wrong value")
    341 		die()
    342 	}
    343 }
    344 
    345 type I interface {
    346 	M()
    347 }
    348 
    349 // pointer receiver, so no wrapper in i.M()
    350 type T1 struct{}
    351 
    352 func (*T1) M() {
    353 	mustRecoverBody(doubleRecover(), recover(), recover(), 9)
    354 }
    355 
    356 func test9() {
    357 	var i I = &T1{}
    358 	defer i.M()
    359 	panic(9)
    360 }
    361 
    362 func test9reflect1() {
    363 	f := reflect.ValueOf(&T1{}).Method(0).Interface().(func())
    364 	defer f()
    365 	panic(9)
    366 }
    367 
    368 func test9reflect2() {
    369 	f := reflect.TypeOf(&T1{}).Method(0).Func.Interface().(func(*T1))
    370 	defer f(&T1{})
    371 	panic(9)
    372 }
    373 
    374 // word-sized value receiver, so no wrapper in i.M()
    375 type T2 uintptr
    376 
    377 func (T2) M() {
    378 	mustRecoverBody(doubleRecover(), recover(), recover(), 10)
    379 }
    380 
    381 func test10() {
    382 	var i I = T2(0)
    383 	defer i.M()
    384 	panic(10)
    385 }
    386 
    387 func test10reflect1() {
    388 	f := reflect.ValueOf(T2(0)).Method(0).Interface().(func())
    389 	defer f()
    390 	panic(10)
    391 }
    392 
    393 func test10reflect2() {
    394 	f := reflect.TypeOf(T2(0)).Method(0).Func.Interface().(func(T2))
    395 	defer f(T2(0))
    396 	panic(10)
    397 }
    398 
    399 // tiny receiver, so basic wrapper in i.M()
    400 type T3 struct{}
    401 
    402 func (T3) M() {
    403 	mustRecoverBody(doubleRecover(), recover(), recover(), 11)
    404 }
    405 
    406 func test11() {
    407 	var i I = T3{}
    408 	defer i.M()
    409 	panic(11)
    410 }
    411 
    412 func test11reflect1() {
    413 	f := reflect.ValueOf(T3{}).Method(0).Interface().(func())
    414 	defer f()
    415 	panic(11)
    416 }
    417 
    418 func test11reflect2() {
    419 	f := reflect.TypeOf(T3{}).Method(0).Func.Interface().(func(T3))
    420 	defer f(T3{})
    421 	panic(11)
    422 }
    423 
    424 // tiny receiver, so basic wrapper in i.M()
    425 type T3deeper struct{}
    426 
    427 func (T3deeper) M() {
    428 	badstate() // difference from T3
    429 	mustRecoverBody(doubleRecover(), recover(), recover(), 111)
    430 }
    431 
    432 func test111() {
    433 	var i I = T3deeper{}
    434 	defer i.M()
    435 	panic(111)
    436 }
    437 
    438 type Tiny struct{}
    439 
    440 func (Tiny) M() {
    441 	panic(112)
    442 }
    443 
    444 // i.M is a wrapper, and i.M panics.
    445 //
    446 // This is a torture test for an old implementation of recover that
    447 // tried to deal with wrapper functions by doing some argument
    448 // positioning math on both entry and exit. Doing anything on exit
    449 // is a problem because sometimes functions exit via panic instead
    450 // of an ordinary return, so panic would have to know to do the
    451 // same math when unwinding the stack. It gets complicated fast.
    452 // This particular test never worked with the old scheme, because
    453 // panic never did the right unwinding math.
    454 //
    455 // The new scheme adjusts Panic.argp on entry to a wrapper.
    456 // It has no exit work, so if a wrapper is interrupted by a panic,
    457 // there's no cleanup that panic itself must do.
    458 // This test just works now.
    459 func badstate() {
    460 	defer func() {
    461 		recover()
    462 	}()
    463 	var i I = Tiny{}
    464 	i.M()
    465 }
    466 
    467 // large receiver, so basic wrapper in i.M()
    468 type T4 [2]string
    469 
    470 func (T4) M() {
    471 	mustRecoverBody(doubleRecover(), recover(), recover(), 12)
    472 }
    473 
    474 func test12() {
    475 	var i I = T4{}
    476 	defer i.M()
    477 	panic(12)
    478 }
    479 
    480 func test12reflect1() {
    481 	f := reflect.ValueOf(T4{}).Method(0).Interface().(func())
    482 	defer f()
    483 	panic(12)
    484 }
    485 
    486 func test12reflect2() {
    487 	f := reflect.TypeOf(T4{}).Method(0).Func.Interface().(func(T4))
    488 	defer f(T4{})
    489 	panic(12)
    490 }
    491 
    492 // enormous receiver, so wrapper splits stack to call M
    493 type T5 [8192]byte
    494 
    495 func (T5) M() {
    496 	mustRecoverBody(doubleRecover(), recover(), recover(), 13)
    497 }
    498 
    499 func test13() {
    500 	var i I = T5{}
    501 	defer i.M()
    502 	panic(13)
    503 }
    504 
    505 func test13reflect1() {
    506 	f := reflect.ValueOf(T5{}).Method(0).Interface().(func())
    507 	defer f()
    508 	panic(13)
    509 }
    510 
    511 func test13reflect2() {
    512 	f := reflect.TypeOf(T5{}).Method(0).Func.Interface().(func(T5))
    513 	defer f(T5{})
    514 	panic(13)
    515 }
    516 
    517 // enormous receiver + enormous method frame, so wrapper splits stack to call M,
    518 // and then M splits stack to allocate its frame.
    519 // recover must look back two frames to find the panic.
    520 type T6 [8192]byte
    521 
    522 var global byte
    523 
    524 func (T6) M() {
    525 	var x [8192]byte
    526 	x[0] = 1
    527 	x[1] = 2
    528 	for i := range x {
    529 		global += x[i]
    530 	}
    531 	mustRecoverBody(doubleRecover(), recover(), recover(), 14)
    532 }
    533 
    534 func test14() {
    535 	var i I = T6{}
    536 	defer i.M()
    537 	panic(14)
    538 }
    539 
    540 func test14reflect1() {
    541 	f := reflect.ValueOf(T6{}).Method(0).Interface().(func())
    542 	defer f()
    543 	panic(14)
    544 }
    545 
    546 func test14reflect2() {
    547 	f := reflect.TypeOf(T6{}).Method(0).Func.Interface().(func(T6))
    548 	defer f(T6{})
    549 	panic(14)
    550 }
    551 
    552 // function created by reflect.MakeFunc
    553 
    554 func reflectFunc(args []reflect.Value) (results []reflect.Value) {
    555 	mustRecoverBody(doubleRecover(), recover(), recover(), 15)
    556 	return nil
    557 }
    558 
    559 func test15() {
    560 	f := reflect.MakeFunc(reflect.TypeOf((func())(nil)), reflectFunc).Interface().(func())
    561 	defer f()
    562 	panic(15)
    563 }
    564 
    565 func reflectFunc2(args []reflect.Value) (results []reflect.Value) {
    566 	// This will call reflectFunc3
    567 	args[0].Interface().(func())()
    568 	return nil
    569 }
    570 
    571 func reflectFunc3(args []reflect.Value) (results []reflect.Value) {
    572 	if v := recover(); v != nil {
    573 		println("spurious recover", v)
    574 		die()
    575 	}
    576 	return nil
    577 }
    578 
    579 func test16() {
    580 	defer mustRecover(16)
    581 
    582 	f2 := reflect.MakeFunc(reflect.TypeOf((func(func()))(nil)), reflectFunc2).Interface().(func(func()))
    583 	f3 := reflect.MakeFunc(reflect.TypeOf((func())(nil)), reflectFunc3).Interface().(func())
    584 	defer f2(f3)
    585 
    586 	panic(16)
    587 }
    588