1 // Copyright (c) Microsoft. All rights reserved. 2 // Licensed under the MIT license. See LICENSE file in the project root for 3 // full license information. 4 5 /* 6 Tests some throw and rethrow situations (mostly CRT a test) 7 */ 8 9 10 #include <stdlib.h> 11 #include <stdio.h> 12 13 14 #define FALSE 0 15 #define TRUE 1 16 #define NO_CTOR_THROW 1 17 #define NO_DTOR_THROW 2 18 19 20 int Object[100]; 21 int CurrentObjectNumber, Test; 22 int MaxTest = 10; 23 int MaxObjectCount = 1; 24 int Fail; 25 26 27 void FAIL(int i) 28 { 29 printf("FAILED on %d\n", i); 30 Fail++; 31 } 32 33 void dealloc(int i, int no_throw) 34 { 35 /* Make sure i is valid, and object exists */ 36 if(i<0 || i>=MaxObjectCount || !Object[i]) 37 FAIL(i); 38 39 Object[i] = 0; 40 } 41 42 void alloc(int i, int no_throw) 43 { 44 if(CurrentObjectNumber > MaxObjectCount) 45 MaxObjectCount = CurrentObjectNumber; 46 47 /* Object already exists? */ 48 if(Object[i]) FAIL(i); 49 50 Object[i] = 1; 51 } 52 53 class B 54 { 55 public: 56 int i; 57 int flag; 58 B(); 59 B(int); 60 B(const B &b); 61 ~B(); 62 }; 63 64 B::B() 65 { 66 i = CurrentObjectNumber++; 67 printf("B ctor. i = %d\n", i); 68 alloc(i, FALSE); 69 } 70 71 B::B(int f) 72 { 73 i = CurrentObjectNumber++; 74 flag = f; 75 printf("B ctor. i = %d\n", i); 76 alloc(i, flag==NO_CTOR_THROW); 77 } 78 79 B::B(const B &b) 80 { 81 i = CurrentObjectNumber++; 82 printf("B copy ctor. i = %d\n", i); 83 alloc(i, FALSE); 84 } 85 86 B::~B() 87 { 88 printf("B dtor. i = %d\n", i); 89 dealloc(i, flag==NO_DTOR_THROW); 90 } 91 92 class A 93 { 94 public: 95 int i; 96 A(); 97 A(int) 98 { 99 i = CurrentObjectNumber++; 100 printf("A(int) ctor. i = %d\n", i); 101 alloc(i, FALSE); 102 } 103 A operator+(A a); 104 A(const A &a) 105 { 106 /* Try objects in ctor */ 107 B b1 = NO_DTOR_THROW, b2 = NO_DTOR_THROW; 108 109 i = CurrentObjectNumber++; 110 printf("A copy ctor. i = %d\n", i); 111 alloc(i, FALSE); 112 } 113 114 ~A(){ 115 /* Try objects in dtor */ 116 B b1 = NO_CTOR_THROW, b2 = NO_CTOR_THROW; 117 118 printf("A dtor. i = %d\n", i); 119 dealloc(i, FALSE); 120 }; 121 }; 122 123 A::A() 124 { 125 i=CurrentObjectNumber++; 126 printf("A ctor. i = %d\n", i); 127 alloc(i, FALSE); 128 } 129 130 A A::operator+(A a) 131 { 132 printf("A%d + A%d\n", i, a.i); 133 return A(); 134 } 135 136 void Throwa(A a) 137 { 138 printf("Throwing\n"); 139 throw a; 140 } 141 142 void bar() 143 { 144 A a; 145 146 Throwa(a); 147 } 148 149 void foobar() 150 { 151 B b; 152 bar(); 153 } 154 155 // Somehow, inlining this causes different unwinding order.. 156 157 __declspec(noinline) void Rethrow2() 158 { 159 A a; 160 printf("Rethrowing\n"); 161 throw; 162 } 163 164 #pragma inline_depth(0) 165 void Rethrow() 166 { 167 Rethrow2(); 168 } 169 #pragma inline_depth() 170 171 void foobar2() 172 { 173 B b; 174 175 try{ 176 A a; 177 bar(); 178 }catch(A a){ 179 printf("In catch;\n"); 180 Rethrow(); 181 } 182 } 183 184 void foobar3() 185 { 186 B b; 187 188 try{ 189 A a; 190 bar(); 191 }catch(A a){ 192 printf("In catch\n"); 193 A a2; 194 195 printf("Throwing new a\n"); 196 throw a2; 197 } 198 } 199 200 void foobar4() 201 { 202 B b; 203 204 try{ 205 B b; 206 try{ 207 A a1, a2; 208 try { 209 A a1, a2; 210 foobar2(); 211 }catch(A a){ 212 printf("In catch #1\n"); 213 B b; 214 printf("Rethrowing\n"); 215 throw; 216 } 217 }catch(A &a){ 218 printf("In catch #2\n"); 219 A a2; 220 221 printf("Throwing new a\n"); 222 throw a; 223 } 224 }catch(A a){ 225 printf("In catch #3\n"); 226 B b; 227 printf("Rethrowing\n"); 228 throw; 229 } 230 } 231 232 __declspec(noinline) void throw_B_2() 233 { 234 B b; 235 printf("Throwing a new b\n"); 236 throw b; 237 } 238 239 #pragma inline_depth(0) 240 void throw_B() 241 { 242 throw_B_2(); 243 } 244 #pragma inline_depth() 245 246 247 void foobar5() 248 { 249 try { 250 B b1; 251 try { 252 B b2; 253 try { 254 B b3; 255 foobar(); 256 }catch(B b){ 257 printf("In catch #1\n"); 258 FAIL(-1); 259 } 260 FAIL(-1); 261 }catch(A a){ 262 A a2; 263 printf("In catch #2\n"); 264 throw_B(); 265 } 266 FAIL(-1); 267 }catch(B b){ 268 printf("In catch #3\n"); 269 printf("Throwing a new a\n"); 270 throw A(); 271 } 272 FAIL(-1); 273 } 274 275 276 /* Simple throw with unwinds */ 277 void test1() 278 { 279 A a; 280 foobar(); 281 } 282 283 /* Throw followed by a rethrow */ 284 void test2() 285 { 286 A a; 287 foobar2(); 288 } 289 290 /* Throw followed by a new throw */ 291 void test3() 292 { 293 A a; 294 foobar3(); 295 } 296 297 /* Nested trys with rethrow/throw/rethrow */ 298 void test4() 299 { 300 A a; 301 foobar4(); 302 } 303 304 /* Makes sure a new throw skips appropriate unwound frames. */ 305 void test5() 306 { 307 A a; 308 foobar5(); 309 } 310 311 // Tests 3 level of new throw 312 void test6() 313 { 314 try{ 315 B b1; 316 try{ 317 B b2; 318 try{ 319 B b3; 320 printf("Throwing a b\n"); 321 throw(b3); 322 }catch(B b){ 323 B b4; 324 printf("In catch #1\n"); 325 printf("Throwing a new b\n"); 326 throw(b4); 327 } 328 FAIL(-1); 329 }catch(B b){ 330 B b5; 331 printf("In catch #2\n"); 332 printf("Throwing a new b\n"); 333 throw(b5); 334 } 335 FAIL(-1); 336 }catch(B b){ 337 A a1; 338 printf("In catch #3\n"); 339 printf("Throwing a new a\n"); 340 throw(a1); 341 } 342 FAIL(-1); 343 } 344 345 // Testing try/catch inside a catch 346 void test7() 347 { 348 B b1; 349 try{ 350 B b2; 351 try{ 352 B b3; 353 354 printf("Throwing a b\n"); 355 throw(B()); 356 }catch(B b){ 357 B b4; 358 printf("In catch #1\n"); 359 try{ 360 B b5; 361 printf("Rethrowing b\n"); 362 throw; 363 }catch(B b){ 364 B b5; 365 printf("In catch #1 of catch#1\n"); 366 printf("Rethrowing b\n"); 367 throw; 368 } 369 } 370 }catch(B b){ 371 B b6; 372 printf("In catch #2\n"); 373 printf("Throwing a new A\n"); 374 throw(A()); 375 } 376 } 377 378 void ThrowB() 379 { 380 B b; 381 382 throw(B()); 383 } 384 385 void bar8() 386 { 387 try{ 388 B b5; 389 printf("Rethrowing b\n"); 390 Rethrow(); 391 }catch(B b){ 392 B b5; 393 printf("In catch #1 of catch#1\n"); 394 printf("Rethrowing b\n"); 395 Rethrow(); 396 } 397 } 398 399 void foo8() 400 { 401 B b; 402 try{ 403 B b3; 404 405 printf("Throwing a b\n"); 406 ThrowB(); 407 }catch(B b){ 408 B b4; 409 printf("In catch #1\n"); 410 bar8(); 411 } 412 } 413 414 // Testing call to try/catch function inside a catch 415 void test8() 416 { 417 B b1; 418 try{ 419 B b2; 420 foo8(); 421 }catch(B b){ 422 B b6; 423 printf("In catch #2\n"); 424 printf("Throwing a new A\n"); 425 throw(A()); 426 } 427 } 428 429 void foo9() 430 { 431 try { 432 puts("Rethrow"); 433 throw; 434 }catch(...){ 435 puts("In catch #2"); 436 } 437 } 438 439 void test9() 440 { 441 try{ 442 B b; 443 puts("Throwing B"); 444 throw b; 445 }catch(...){ 446 puts("In catch #1"); 447 foo9(); 448 } 449 puts("End of test9, throwing a A"); 450 throw A(); 451 } 452 453 void foo10() 454 { 455 try { 456 puts("Throwing a new B()"); 457 throw B(); 458 }catch(...){ 459 puts("In catch #2"); 460 } 461 } 462 463 void test10() 464 { 465 try{ 466 B b; 467 puts("Throwing B"); 468 throw b; 469 }catch(...){ 470 puts("In catch #1"); 471 foo10(); 472 } 473 puts("End of test10, throwing a A"); 474 throw A(); 475 } 476 477 int main() 478 { 479 int i; 480 481 /* Call test(), with a different ctor/dtor throwing each time */ 482 for(Test = 1; Test <= MaxTest; Test++) { 483 484 CurrentObjectNumber = 0; 485 486 printf("\nTest #%d\n", Test); 487 488 try { 489 switch(Test){ 490 case 1: 491 test1(); 492 break; 493 case 2: 494 test2(); 495 break; 496 case 3: 497 test3(); 498 break; 499 case 4: 500 test4(); 501 break; 502 case 5: 503 test5(); 504 break; 505 case 6: 506 test6(); 507 break; 508 case 7: 509 test7(); 510 break; 511 case 8: 512 test8(); 513 break; 514 case 9: 515 test9(); 516 break; 517 case 10: 518 test10(); 519 break; 520 } 521 522 FAIL(-1); 523 524 }catch(A a){ 525 printf("In main's catch\n"); 526 }catch(...){ 527 FAIL(-1); 528 } 529 530 /* Any objects which didn't get dtor'd? */ 531 for(i = 0; i < MaxObjectCount; i++) { 532 if(Object[i]) { 533 FAIL(i); 534 Object[i] = 0; 535 } 536 } 537 538 printf("\n"); 539 } 540 541 printf("\n"); 542 if(Fail) 543 printf("FAILED %d tests\n", Fail); 544 else 545 printf("Passed\n"); 546 547 } 548