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
FAIL(int i)27 void FAIL(int i)
28 {
29 printf("FAILED on %d\n", i);
30 Fail++;
31 }
32
dealloc(int i,int no_throw)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
alloc(int i,int no_throw)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
B()64 B::B()
65 {
66 i = CurrentObjectNumber++;
67 printf("B ctor. i = %d\n", i);
68 alloc(i, FALSE);
69 }
70
B(int f)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
B(const B & b)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
~B()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();
A(int)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);
A(const 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
~A()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
A()123 A::A()
124 {
125 i=CurrentObjectNumber++;
126 printf("A ctor. i = %d\n", i);
127 alloc(i, FALSE);
128 }
129
operator +(A a)130 A A::operator+(A a)
131 {
132 printf("A%d + A%d\n", i, a.i);
133 return A();
134 }
135
Throwa(A a)136 void Throwa(A a)
137 {
138 printf("Throwing\n");
139 throw a;
140 }
141
bar()142 void bar()
143 {
144 A a;
145
146 Throwa(a);
147 }
148
foobar()149 void foobar()
150 {
151 B b;
152 bar();
153 }
154
155 // Somehow, inlining this causes different unwinding order..
156
Rethrow2()157 __declspec(noinline) void Rethrow2()
158 {
159 A a;
160 printf("Rethrowing\n");
161 throw;
162 }
163
164 #pragma inline_depth(0)
Rethrow()165 void Rethrow()
166 {
167 Rethrow2();
168 }
169 #pragma inline_depth()
170
foobar2()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
foobar3()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
foobar4()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
throw_B_2()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)
throw_B()240 void throw_B()
241 {
242 throw_B_2();
243 }
244 #pragma inline_depth()
245
246
foobar5()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 */
test1()277 void test1()
278 {
279 A a;
280 foobar();
281 }
282
283 /* Throw followed by a rethrow */
test2()284 void test2()
285 {
286 A a;
287 foobar2();
288 }
289
290 /* Throw followed by a new throw */
test3()291 void test3()
292 {
293 A a;
294 foobar3();
295 }
296
297 /* Nested trys with rethrow/throw/rethrow */
test4()298 void test4()
299 {
300 A a;
301 foobar4();
302 }
303
304 /* Makes sure a new throw skips appropriate unwound frames. */
test5()305 void test5()
306 {
307 A a;
308 foobar5();
309 }
310
311 // Tests 3 level of new throw
test6()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
test7()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
ThrowB()378 void ThrowB()
379 {
380 B b;
381
382 throw(B());
383 }
384
bar8()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
foo8()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
test8()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
foo9()429 void foo9()
430 {
431 try {
432 puts("Rethrow");
433 throw;
434 }catch(...){
435 puts("In catch #2");
436 }
437 }
438
test9()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
foo10()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
test10()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
main()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