github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/runtime/defer_test.go (about) 1 // Copyright 2019 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package runtime_test 6 7 import ( 8 "reflect" 9 "runtime" 10 "testing" 11 ) 12 13 // Make sure open-coded defer exit code is not lost, even when there is an 14 // unconditional panic (hence no return from the function) 15 func TestUnconditionalPanic(t *testing.T) { 16 defer func() { 17 if recover() != "testUnconditional" { 18 t.Fatal("expected unconditional panic") 19 } 20 }() 21 panic("testUnconditional") 22 } 23 24 var glob int = 3 25 26 // Test an open-coded defer and non-open-coded defer - make sure both defers run 27 // and call recover() 28 func TestOpenAndNonOpenDefers(t *testing.T) { 29 for { 30 // Non-open defer because in a loop 31 defer func(n int) { 32 if recover() != "testNonOpenDefer" { 33 t.Fatal("expected testNonOpen panic") 34 } 35 }(3) 36 if glob > 2 { 37 break 38 } 39 } 40 testOpen(t, 47) 41 panic("testNonOpenDefer") 42 } 43 44 //go:noinline 45 func testOpen(t *testing.T, arg int) { 46 defer func(n int) { 47 if recover() != "testOpenDefer" { 48 t.Fatal("expected testOpen panic") 49 } 50 }(4) 51 if arg > 2 { 52 panic("testOpenDefer") 53 } 54 } 55 56 // Test a non-open-coded defer and an open-coded defer - make sure both defers run 57 // and call recover() 58 func TestNonOpenAndOpenDefers(t *testing.T) { 59 testOpen(t, 47) 60 for { 61 // Non-open defer because in a loop 62 defer func(n int) { 63 if recover() != "testNonOpenDefer" { 64 t.Fatal("expected testNonOpen panic") 65 } 66 }(3) 67 if glob > 2 { 68 break 69 } 70 } 71 panic("testNonOpenDefer") 72 } 73 74 var list []int 75 76 // Make sure that conditional open-coded defers are activated correctly and run in 77 // the correct order. 78 func TestConditionalDefers(t *testing.T) { 79 list = make([]int, 0, 10) 80 81 defer func() { 82 if recover() != "testConditional" { 83 t.Fatal("expected panic") 84 } 85 want := []int{4, 2, 1} 86 if !reflect.DeepEqual(want, list) { 87 t.Fatalf("wanted %v, got %v", want, list) 88 } 89 90 }() 91 testConditionalDefers(8) 92 } 93 94 func testConditionalDefers(n int) { 95 doappend := func(i int) { 96 list = append(list, i) 97 } 98 99 defer doappend(1) 100 if n > 5 { 101 defer doappend(2) 102 if n > 8 { 103 defer doappend(3) 104 } else { 105 defer doappend(4) 106 } 107 } 108 panic("testConditional") 109 } 110 111 // Test that there is no compile-time or run-time error if an open-coded defer 112 // call is removed by constant propagation and dead-code elimination. 113 func TestDisappearingDefer(t *testing.T) { 114 switch runtime.GOOS { 115 case "invalidOS": 116 defer func() { 117 t.Fatal("Defer shouldn't run") 118 }() 119 } 120 } 121 122 // This tests an extra recursive panic behavior that is only specified in the 123 // code. Suppose a first panic P1 happens and starts processing defer calls. If a 124 // second panic P2 happens while processing defer call D in frame F, then defer 125 // call processing is restarted (with some potentially new defer calls created by 126 // D or its callees). If the defer processing reaches the started defer call D 127 // again in the defer stack, then the original panic P1 is aborted and cannot 128 // continue panic processing or be recovered. If the panic P2 does a recover at 129 // some point, it will naturally remove the original panic P1 from the stack 130 // (since the original panic had to be in frame F or a descendant of F). 131 func TestAbortedPanic(t *testing.T) { 132 defer func() { 133 r := recover() 134 if r != nil { 135 t.Fatalf("wanted nil recover, got %v", r) 136 } 137 }() 138 defer func() { 139 r := recover() 140 if r != "panic2" { 141 t.Fatalf("wanted %v, got %v", "panic2", r) 142 } 143 }() 144 defer func() { 145 panic("panic2") 146 }() 147 panic("panic1") 148 } 149 150 // This tests that recover() does not succeed unless it is called directly from a 151 // defer function that is directly called by the panic. Here, we first call it 152 // from a defer function that is created by the defer function called directly by 153 // the panic. In 154 func TestRecoverMatching(t *testing.T) { 155 defer func() { 156 r := recover() 157 if r != "panic1" { 158 t.Fatalf("wanted %v, got %v", "panic1", r) 159 } 160 }() 161 defer func() { 162 defer func() { 163 // Shouldn't succeed, even though it is called directly 164 // from a defer function, since this defer function was 165 // not directly called by the panic. 166 r := recover() 167 if r != nil { 168 t.Fatalf("wanted nil recover, got %v", r) 169 } 170 }() 171 }() 172 panic("panic1") 173 } 174 175 type nonSSAable [128]byte 176 177 type bigStruct struct { 178 x, y, z, w, p, q int64 179 } 180 181 type containsBigStruct struct { 182 element bigStruct 183 } 184 185 func mknonSSAable() nonSSAable { 186 globint1++ 187 return nonSSAable{0, 0, 0, 0, 5} 188 } 189 190 var globint1, globint2, globint3 int 191 192 //go:noinline 193 func sideeffect(n int64) int64 { 194 globint2++ 195 return n 196 } 197 198 func sideeffect2(in containsBigStruct) containsBigStruct { 199 globint3++ 200 return in 201 } 202 203 // Test that nonSSAable arguments to defer are handled correctly and only evaluated once. 204 func TestNonSSAableArgs(t *testing.T) { 205 globint1 = 0 206 globint2 = 0 207 globint3 = 0 208 var save1 byte 209 var save2 int64 210 var save3 int64 211 var save4 int64 212 213 defer func() { 214 if globint1 != 1 { 215 t.Fatalf("globint1: wanted: 1, got %v", globint1) 216 } 217 if save1 != 5 { 218 t.Fatalf("save1: wanted: 5, got %v", save1) 219 } 220 if globint2 != 1 { 221 t.Fatalf("globint2: wanted: 1, got %v", globint2) 222 } 223 if save2 != 2 { 224 t.Fatalf("save2: wanted: 2, got %v", save2) 225 } 226 if save3 != 4 { 227 t.Fatalf("save3: wanted: 4, got %v", save3) 228 } 229 if globint3 != 1 { 230 t.Fatalf("globint3: wanted: 1, got %v", globint3) 231 } 232 if save4 != 4 { 233 t.Fatalf("save1: wanted: 4, got %v", save4) 234 } 235 }() 236 237 // Test function returning a non-SSAable arg 238 defer func(n nonSSAable) { 239 save1 = n[4] 240 }(mknonSSAable()) 241 // Test composite literal that is not SSAable 242 defer func(b bigStruct) { 243 save2 = b.y 244 }(bigStruct{1, 2, 3, 4, 5, sideeffect(6)}) 245 246 // Test struct field reference that is non-SSAable 247 foo := containsBigStruct{} 248 foo.element.z = 4 249 defer func(element bigStruct) { 250 save3 = element.z 251 }(foo.element) 252 defer func(element bigStruct) { 253 save4 = element.z 254 }(sideeffect2(foo).element) 255 } 256 257 //go:noinline 258 func doPanic() { 259 panic("Test panic") 260 } 261 262 func TestDeferForFuncWithNoExit(t *testing.T) { 263 cond := 1 264 defer func() { 265 if cond != 2 { 266 t.Fatalf("cond: wanted 2, got %v", cond) 267 } 268 if recover() != "Test panic" { 269 t.Fatal("Didn't find expected panic") 270 } 271 }() 272 x := 0 273 // Force a stack copy, to make sure that the &cond pointer passed to defer 274 // function is properly updated. 275 growStackIter(&x, 1000) 276 cond = 2 277 doPanic() 278 279 // This function has no exit/return, since it ends with an infinite loop 280 for { 281 } 282 } 283 284 // Test case approximating issue #37664, where a recursive function (interpreter) 285 // may do repeated recovers/re-panics until it reaches the frame where the panic 286 // can actually be handled. The recurseFnPanicRec() function is testing that there 287 // are no stale defer structs on the defer chain after the interpreter() sequence, 288 // by writing a bunch of 0xffffffffs into several recursive stack frames, and then 289 // doing a single panic-recover which would invoke any such stale defer structs. 290 func TestDeferWithRepeatedRepanics(t *testing.T) { 291 interpreter(0, 6, 2) 292 recurseFnPanicRec(0, 10) 293 interpreter(0, 5, 1) 294 recurseFnPanicRec(0, 10) 295 interpreter(0, 6, 3) 296 recurseFnPanicRec(0, 10) 297 } 298 299 func interpreter(level int, maxlevel int, rec int) { 300 defer func() { 301 e := recover() 302 if e == nil { 303 return 304 } 305 if level != e.(int) { 306 //fmt.Fprintln(os.Stderr, "re-panicing, level", level) 307 panic(e) 308 } 309 //fmt.Fprintln(os.Stderr, "Recovered, level", level) 310 }() 311 if level+1 < maxlevel { 312 interpreter(level+1, maxlevel, rec) 313 } else { 314 //fmt.Fprintln(os.Stderr, "Initiating panic") 315 panic(rec) 316 } 317 } 318 319 func recurseFnPanicRec(level int, maxlevel int) { 320 defer func() { 321 recover() 322 }() 323 recurseFn(level, maxlevel) 324 } 325 326 var saveInt uint32 327 328 func recurseFn(level int, maxlevel int) { 329 a := [40]uint32{0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff} 330 if level+1 < maxlevel { 331 // Make sure a array is referenced, so it is not optimized away 332 saveInt = a[4] 333 recurseFn(level+1, maxlevel) 334 } else { 335 panic("recurseFn panic") 336 } 337 } 338 339 // Try to reproduce issue #37688, where a pointer to an open-coded defer struct is 340 // mistakenly held, and that struct keeps a pointer to a stack-allocated defer 341 // struct, and that stack-allocated struct gets overwritten or the stack gets 342 // moved, so a memory error happens on GC. 343 func TestIssue37688(t *testing.T) { 344 for j := 0; j < 10; j++ { 345 g2() 346 g3() 347 } 348 } 349 350 type foo struct { 351 } 352 353 //go:noinline 354 func (f *foo) method1() { 355 } 356 357 //go:noinline 358 func (f *foo) method2() { 359 } 360 361 func g2() { 362 var a foo 363 ap := &a 364 // The loop forces this defer to be heap-allocated and the remaining two 365 // to be stack-allocated. 366 for i := 0; i < 1; i++ { 367 defer ap.method1() 368 } 369 defer ap.method2() 370 defer ap.method1() 371 ff1(ap, 1, 2, 3, 4, 5, 6, 7, 8, 9) 372 // Try to get the stack to be moved by growing it too large, so 373 // existing stack-allocated defer becomes invalid. 374 rec1(2000) 375 } 376 377 func g3() { 378 // Mix up the stack layout by adding in an extra function frame 379 g2() 380 } 381 382 var globstruct struct { 383 a, b, c, d, e, f, g, h, i int 384 } 385 386 func ff1(ap *foo, a, b, c, d, e, f, g, h, i int) { 387 defer ap.method1() 388 389 // Make a defer that has a very large set of args, hence big size for the 390 // defer record for the open-coded frame (which means it won't use the 391 // defer pool) 392 defer func(ap *foo, a, b, c, d, e, f, g, h, i int) { 393 if v := recover(); v != nil { 394 } 395 globstruct.a = a 396 globstruct.b = b 397 globstruct.c = c 398 globstruct.d = d 399 globstruct.e = e 400 globstruct.f = f 401 globstruct.g = g 402 globstruct.h = h 403 }(ap, a, b, c, d, e, f, g, h, i) 404 panic("ff1 panic") 405 } 406 407 func rec1(max int) { 408 if max > 0 { 409 rec1(max - 1) 410 } 411 } 412 413 func TestIssue43921(t *testing.T) { 414 defer func() { 415 expect(t, 1, recover()) 416 }() 417 func() { 418 // Prevent open-coded defers 419 for { 420 defer func() {}() 421 break 422 } 423 424 defer func() { 425 defer func() { 426 expect(t, 4, recover()) 427 }() 428 panic(4) 429 }() 430 panic(1) 431 432 }() 433 } 434 435 func expect(t *testing.T, n int, err any) { 436 if n != err { 437 t.Fatalf("have %v, want %v", err, n) 438 } 439 } 440 441 func TestIssue43920(t *testing.T) { 442 var steps int 443 444 defer func() { 445 expect(t, 1, recover()) 446 }() 447 defer func() { 448 defer func() { 449 defer func() { 450 expect(t, 5, recover()) 451 }() 452 defer panic(5) 453 func() { 454 panic(4) 455 }() 456 }() 457 defer func() { 458 expect(t, 3, recover()) 459 }() 460 defer panic(3) 461 }() 462 func() { 463 defer step(t, &steps, 1) 464 panic(1) 465 }() 466 } 467 468 func step(t *testing.T, steps *int, want int) { 469 *steps++ 470 if *steps != want { 471 t.Fatalf("have %v, want %v", *steps, want) 472 } 473 } 474 475 func TestIssue43941(t *testing.T) { 476 var steps int = 7 477 defer func() { 478 step(t, &steps, 14) 479 expect(t, 4, recover()) 480 }() 481 func() { 482 func() { 483 defer func() { 484 defer func() { 485 expect(t, 3, recover()) 486 }() 487 defer panic(3) 488 panic(2) 489 }() 490 defer func() { 491 expect(t, 1, recover()) 492 }() 493 defer panic(1) 494 }() 495 defer func() {}() 496 defer func() {}() 497 defer step(t, &steps, 10) 498 defer step(t, &steps, 9) 499 step(t, &steps, 8) 500 }() 501 func() { 502 defer step(t, &steps, 13) 503 defer step(t, &steps, 12) 504 func() { 505 defer step(t, &steps, 11) 506 panic(4) 507 }() 508 509 // Code below isn't executed, 510 // but removing it breaks the test case. 511 defer func() {}() 512 defer panic(-1) 513 defer step(t, &steps, -1) 514 defer step(t, &steps, -1) 515 defer func() {}() 516 }() 517 }