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