modernc.org/gc@v1.0.1-0.20240304020402-f0dba7c97c2b/testdata/errchk/test/recover.go (about) 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 }