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 9package main 10 11import ( 12 "os" 13 "reflect" 14 "runtime" 15) 16 17func 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 test12() 51 if !interp { 52 test12reflect1() 53 test12reflect2() 54 } 55 test13() 56 if !interp { 57 test13reflect1() 58 test13reflect2() 59 } 60 test14() 61 if !interp { 62 test14reflect1() 63 test14reflect2() 64 test15() 65 } 66} 67 68func die() { 69 runtime.Breakpoint() // can't depend on panic 70} 71 72func mustRecoverBody(v1, v2, v3, x interface{}) { 73 v := v1 74 if v != nil { 75 println("spurious recover", v) 76 die() 77 } 78 v = v2 79 if v == nil { 80 println("missing recover") 81 die() // panic is useless here 82 } 83 if v != x { 84 println("wrong value", v, x) 85 die() 86 } 87 88 // the value should be gone now regardless 89 v = v3 90 if v != nil { 91 println("recover didn't recover") 92 die() 93 } 94} 95 96func doubleRecover() interface{} { 97 return recover() 98} 99 100func mustRecover(x interface{}) { 101 mustRecoverBody(doubleRecover(), recover(), recover(), x) 102} 103 104func mustNotRecover() { 105 v := recover() 106 if v != nil { 107 println("spurious recover", v) 108 die() 109 } 110} 111 112func withoutRecover() { 113 mustNotRecover() // because it's a sub-call 114} 115 116func test1() { 117 defer mustNotRecover() // because mustRecover will squelch it 118 defer mustRecover(1) // because of panic below 119 defer withoutRecover() // should be no-op, leaving for mustRecover to find 120 panic(1) 121} 122 123// Repeat test1 with closures instead of standard function. 124// Interesting because recover bases its decision 125// on the frame pointer of its caller, and a closure's 126// frame pointer is in the middle of its actual arguments 127// (after the hidden ones for the closed-over variables). 128func test1WithClosures() { 129 defer func() { 130 v := recover() 131 if v != nil { 132 println("spurious recover in closure") 133 die() 134 } 135 }() 136 defer func(x interface{}) { 137 mustNotRecover() 138 v := recover() 139 if v == nil { 140 println("missing recover") 141 die() 142 } 143 if v != x { 144 println("wrong value", v, x) 145 die() 146 } 147 }(1) 148 defer func() { 149 mustNotRecover() 150 }() 151 panic(1) 152} 153 154func test2() { 155 // Recover only sees the panic argument 156 // if it is called from a deferred call. 157 // It does not see the panic when called from a call within a deferred call (too late) 158 // nor does it see the panic when it *is* the deferred call (too early). 159 defer mustRecover(2) 160 defer recover() // should be no-op 161 panic(2) 162} 163 164func test3() { 165 defer mustNotRecover() 166 defer func() { 167 recover() // should squelch 168 }() 169 panic(3) 170} 171 172func test4() { 173 // Equivalent to test3 but using defer to make the call. 174 defer mustNotRecover() 175 defer func() { 176 defer recover() // should squelch 177 }() 178 panic(4) 179} 180 181// Check that closures can set output arguments. 182// Run g(). If it panics, return x; else return deflt. 183func try(g func(), deflt interface{}) (x interface{}) { 184 defer func() { 185 if v := recover(); v != nil { 186 x = v 187 } 188 }() 189 defer g() 190 return deflt 191} 192 193// Check that closures can set output arguments. 194// Run g(). If it panics, return x; else return deflt. 195func try1(g func(), deflt interface{}) (x interface{}) { 196 defer func() { 197 if v := recover(); v != nil { 198 x = v 199 } 200 }() 201 defer g() 202 x = deflt 203 return 204} 205 206func test5() { 207 v := try(func() { panic(5) }, 55).(int) 208 if v != 5 { 209 println("wrong value", v, 5) 210 die() 211 } 212 213 s := try(func() {}, "hi").(string) 214 if s != "hi" { 215 println("wrong value", s, "hi") 216 die() 217 } 218 219 v = try1(func() { panic(5) }, 55).(int) 220 if v != 5 { 221 println("try1 wrong value", v, 5) 222 die() 223 } 224 225 s = try1(func() {}, "hi").(string) 226 if s != "hi" { 227 println("try1 wrong value", s, "hi") 228 die() 229 } 230} 231 232// When a deferred big call starts, it must first 233// create yet another stack segment to hold the 234// giant frame for x. Make sure that doesn't 235// confuse recover. 236func big(mustRecover bool) { 237 var x [100000]int 238 x[0] = 1 239 x[99999] = 1 240 _ = x 241 242 v := recover() 243 if mustRecover { 244 if v == nil { 245 println("missing big recover") 246 die() 247 } 248 } else { 249 if v != nil { 250 println("spurious big recover") 251 die() 252 } 253 } 254} 255 256func test6() { 257 defer big(false) 258 defer big(true) 259 panic(6) 260} 261 262func test6WithClosures() { 263 defer func() { 264 var x [100000]int 265 x[0] = 1 266 x[99999] = 1 267 _ = x 268 if recover() != nil { 269 println("spurious big closure recover") 270 die() 271 } 272 }() 273 defer func() { 274 var x [100000]int 275 x[0] = 1 276 x[99999] = 1 277 _ = x 278 if recover() == nil { 279 println("missing big closure recover") 280 die() 281 } 282 }() 283 panic("6WithClosures") 284} 285 286func test7() { 287 ok := false 288 func() { 289 // should panic, then call mustRecover 7, which stops the panic. 290 // then should keep processing ordinary defers earlier than that one 291 // before returning. 292 // this test checks that the defer func on the next line actually runs. 293 defer func() { ok = true }() 294 defer mustRecover(7) 295 panic(7) 296 }() 297 if !ok { 298 println("did not run ok func") 299 die() 300 } 301} 302 303func varargs(s *int, a ...int) { 304 *s = 0 305 for _, v := range a { 306 *s += v 307 } 308 if recover() != nil { 309 *s += 100 310 } 311} 312 313func test8a() (r int) { 314 defer varargs(&r, 1, 2, 3) 315 panic(0) 316} 317 318func test8b() (r int) { 319 defer varargs(&r, 4, 5, 6) 320 return 321} 322 323func test8() { 324 if test8a() != 106 || test8b() != 15 { 325 println("wrong value") 326 die() 327 } 328} 329 330type I interface { 331 M() 332} 333 334// pointer receiver, so no wrapper in i.M() 335type T1 struct{} 336 337func (*T1) M() { 338 mustRecoverBody(doubleRecover(), recover(), recover(), 9) 339} 340 341func test9() { 342 var i I = &T1{} 343 defer i.M() 344 panic(9) 345} 346 347func test9reflect1() { 348 f := reflect.ValueOf(&T1{}).Method(0).Interface().(func()) 349 defer f() 350 panic(9) 351} 352 353func test9reflect2() { 354 f := reflect.TypeOf(&T1{}).Method(0).Func.Interface().(func(*T1)) 355 defer f(&T1{}) 356 panic(9) 357} 358 359// word-sized value receiver, so no wrapper in i.M() 360type T2 uintptr 361 362func (T2) M() { 363 mustRecoverBody(doubleRecover(), recover(), recover(), 10) 364} 365 366func test10() { 367 var i I = T2(0) 368 defer i.M() 369 panic(10) 370} 371 372func test10reflect1() { 373 f := reflect.ValueOf(T2(0)).Method(0).Interface().(func()) 374 defer f() 375 panic(10) 376} 377 378func test10reflect2() { 379 f := reflect.TypeOf(T2(0)).Method(0).Func.Interface().(func(T2)) 380 defer f(T2(0)) 381 panic(10) 382} 383 384// tiny receiver, so basic wrapper in i.M() 385type T3 struct{} 386 387func (T3) M() { 388 mustRecoverBody(doubleRecover(), recover(), recover(), 11) 389} 390 391func test11() { 392 var i I = T3{} 393 defer i.M() 394 panic(11) 395} 396 397func test11reflect1() { 398 f := reflect.ValueOf(T3{}).Method(0).Interface().(func()) 399 defer f() 400 panic(11) 401} 402 403func test11reflect2() { 404 f := reflect.TypeOf(T3{}).Method(0).Func.Interface().(func(T3)) 405 defer f(T3{}) 406 panic(11) 407} 408 409// large receiver, so basic wrapper in i.M() 410type T4 [2]string 411 412func (T4) M() { 413 mustRecoverBody(doubleRecover(), recover(), recover(), 12) 414} 415 416func test12() { 417 var i I = T4{} 418 defer i.M() 419 panic(12) 420} 421 422func test12reflect1() { 423 f := reflect.ValueOf(T4{}).Method(0).Interface().(func()) 424 defer f() 425 panic(12) 426} 427 428func test12reflect2() { 429 f := reflect.TypeOf(T4{}).Method(0).Func.Interface().(func(T4)) 430 defer f(T4{}) 431 panic(12) 432} 433 434// enormous receiver, so wrapper splits stack to call M 435type T5 [8192]byte 436 437func (T5) M() { 438 mustRecoverBody(doubleRecover(), recover(), recover(), 13) 439} 440 441func test13() { 442 var i I = T5{} 443 defer i.M() 444 panic(13) 445} 446 447func test13reflect1() { 448 f := reflect.ValueOf(T5{}).Method(0).Interface().(func()) 449 defer f() 450 panic(13) 451} 452 453func test13reflect2() { 454 f := reflect.TypeOf(T5{}).Method(0).Func.Interface().(func(T5)) 455 defer f(T5{}) 456 panic(13) 457} 458 459// enormous receiver + enormous method frame, so wrapper splits stack to call M, 460// and then M splits stack to allocate its frame. 461// recover must look back two frames to find the panic. 462type T6 [8192]byte 463 464var global byte 465 466func (T6) M() { 467 var x [8192]byte 468 x[0] = 1 469 x[1] = 2 470 for i := range x { 471 global += x[i] 472 } 473 mustRecoverBody(doubleRecover(), recover(), recover(), 14) 474} 475 476func test14() { 477 var i I = T6{} 478 defer i.M() 479 panic(14) 480} 481 482func test14reflect1() { 483 f := reflect.ValueOf(T6{}).Method(0).Interface().(func()) 484 defer f() 485 panic(14) 486} 487 488func test14reflect2() { 489 f := reflect.TypeOf(T6{}).Method(0).Func.Interface().(func(T6)) 490 defer f(T6{}) 491 panic(14) 492} 493 494// function created by reflect.MakeFunc 495 496func reflectFunc(args []reflect.Value) (results []reflect.Value) { 497 mustRecoverBody(doubleRecover(), recover(), recover(), 15) 498 return nil 499} 500 501func test15() { 502 f := reflect.MakeFunc(reflect.TypeOf((func())(nil)), reflectFunc).Interface().(func()) 503 defer f() 504 panic(15) 505} 506