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  * Exercise lots of different kinds of C++ EH frames.  Compile this with
7  * every combination of opts you can to stress the C++ EH frame code in the
8  * backend.
9  */
10 
11 #include <stdio.h>
12 #include <malloc.h>
13 
14 #ifndef ALIGN
15 #define ALIGN 64
16 #endif
17 
18 extern int TestFunc(int, ...);
19 
20 int failures;
21 
22 int global;
23 bool TestFuncThrows;
24 
25 struct SmallObj
26 {
27     virtual ~SmallObj()
28     {
29         TestFunc(1, this);
30     };
31 
32     int x;
33 };
34 
35 struct BigObj
36 {
37     virtual ~BigObj()
38     {
39         TestFunc(1, this);
40     };
41 
42     char x[4096];
43 };
44 
45 int Simple(int arg)
46 {
47     puts(__FUNCTION__);
48     int res = 0;
49     SmallObj f;
50     return TestFunc(1, &f, &res, &arg);
51 }
52 
53 int Try(int arg)
54 {
55     puts(__FUNCTION__);
56     int res = 0;
57     SmallObj f;
58     try {
59         res = TestFunc(1, &f, &res, &arg);
60     } catch (double) {
61         res = TestFunc(2, &f, &res, &arg);
62     }
63     return res;
64 }
65 
66 int GSCookie(int arg)
67 {
68     puts(__FUNCTION__);
69     int res = 0;
70     char buf[16];
71     SmallObj f;
72     return TestFunc(1, buf, &f, &res, &arg);
73 }
74 
75 int TryAndGSCookie(int arg)
76 {
77     puts(__FUNCTION__);
78     int res = 0;
79     char buf[16];
80     SmallObj f;
81     try {
82         res = TestFunc(1, &buf, &f, &res, &arg);
83     } catch (double) {
84         res = TestFunc(2, &buf, &f, &res, &arg);
85     }
86     return res;
87 }
88 
89 int Align(int arg)
90 {
91     puts(__FUNCTION__);
92     int res = 0;
93     __declspec(align(ALIGN)) double d[4];
94     SmallObj f;
95     return TestFunc(1, d, &f, &res, &arg);
96 }
97 
98 int TryAndAlign(int arg)
99 {
100     puts(__FUNCTION__);
101     int res = 0;
102     __declspec(align(ALIGN)) double d[4];
103     SmallObj f;
104     try {
105         res = TestFunc(1, d, &f, &res, &arg);
106     } catch (double) {
107         res = TestFunc(2, d, &f, &res, &arg);
108     }
109     return res;
110 }
111 
112 int GSCookieAndAlign(int arg)
113 {
114     puts(__FUNCTION__);
115     int res = 0;
116     char buf[16];
117     __declspec(align(ALIGN)) double d[4];
118     SmallObj f;
119     return TestFunc(1, buf, d, &f, &res, &arg);
120 }
121 
122 int TryAndGSCookieAndAlign(int arg)
123 {
124     puts(__FUNCTION__);
125     int res = 0;
126     char buf[16];
127     __declspec(align(ALIGN)) double d[4];
128     SmallObj f;
129     try {
130         res = TestFunc(1, buf, d, &f, &res, &arg);
131     } catch (double) {
132         res = TestFunc(2, buf, d, &f, &res, &arg);
133     }
134     return res;
135 }
136 
137 int Alloca(int arg)
138 {
139     puts(__FUNCTION__);
140     int res = 0;
141     SmallObj f;
142     return TestFunc(1, _alloca(global), &f, &res, &arg);
143 }
144 
145 int TryAndAlloca(int arg)
146 {
147     puts(__FUNCTION__);
148     int res = 0;
149     SmallObj f;
150     try {
151         res = TestFunc(1, _alloca(global), &f, &res, &arg);
152     } catch (double) {
153         res = TestFunc(2, &f, &res, &arg);
154     }
155     return res;
156 }
157 
158 int GSCookieAndAlloca(int arg)
159 {
160     puts(__FUNCTION__);
161     int res = 0;
162     char buf[16];
163     SmallObj f;
164     return TestFunc(1, buf, _alloca(global), &f, &res, &arg);
165 }
166 
167 int TryAndGSCookieAndAlloca(int arg)
168 {
169     puts(__FUNCTION__);
170     int res = 0;
171     char buf[16];
172     SmallObj f;
173     try {
174         res = TestFunc(1, &buf, _alloca(global), &f, &res, &arg);
175     } catch (double) {
176         res = TestFunc(2, &buf, &f, &res, &arg);
177     }
178     return res;
179 }
180 
181 int AlignAndAlloca(int arg)
182 {
183     puts(__FUNCTION__);
184     int res = 0;
185     __declspec(align(ALIGN)) double d[4];
186     SmallObj f;
187     return TestFunc(1, d, _alloca(global), &f, &res, &arg);
188 }
189 
190 int TryAndAlignAndAlloca(int arg)
191 {
192     puts(__FUNCTION__);
193     int res = 0;
194     __declspec(align(ALIGN)) double d[4];
195     SmallObj f;
196     try {
197         res = TestFunc(1, d, _alloca(global), &f, &res, &arg);
198     } catch (double) {
199         res = TestFunc(2, d, &f, &res, &arg);
200     }
201     return res;
202 }
203 
204 int GSCookieAndAlignAndAlloca(int arg)
205 {
206     puts(__FUNCTION__);
207     int res = 0;
208     char buf[16];
209     __declspec(align(ALIGN)) double d[4];
210     SmallObj f;
211     return TestFunc(1, buf, d, _alloca(global), &f, &res, &arg);
212 }
213 
214 int TryAndGSCookieAndAlignAndAlloca(int arg)
215 {
216     puts(__FUNCTION__);
217     int res = 0;
218     char buf[16];
219     __declspec(align(ALIGN)) double d[4];
220     SmallObj f;
221     try {
222         res = TestFunc(1, buf, d, _alloca(global), &f, &res, &arg);
223     } catch (double) {
224         res = TestFunc(2, buf, d, &f, &res, &arg);
225     }
226     return res;
227 }
228 
229 /* The *AndBigLocals set of functions try to trigger EBP adjustment */
230 
231 int BigLocals(int arg)
232 {
233     puts(__FUNCTION__);
234     int res = 0;
235     BigObj f1;
236     return TestFunc(1, &f1, &res, &res, &res, &res, &res, &arg);
237 }
238 
239 int TryAndBigLocals(int arg)
240 {
241     puts(__FUNCTION__);
242     int res = 0;
243     BigObj f1;
244     try {
245         res = TestFunc(1, &f1, &res, &res, &res, &res, &res, &arg);
246     } catch (double) {
247         res = TestFunc(2, &f1, &res, &res, &res, &res, &res, &arg);
248     }
249     return res;
250 }
251 
252 int GSCookieAndBigLocals(int arg)
253 {
254     puts(__FUNCTION__);
255     int res = 0;
256     char buf[16];
257     BigObj f1;
258     return TestFunc(1, buf, &f1, &res, &res, &res, &res, &res, &arg);
259 }
260 
261 int TryAndGSCookieAndBigLocals(int arg)
262 {
263     puts(__FUNCTION__);
264     int res = 0;
265     char buf[16];
266     BigObj f1;
267     try {
268         res = TestFunc(1, &buf, &f1, &res, &res, &res, &res, &res, &arg);
269     } catch (double) {
270         res = TestFunc(2, &buf, &f1, &res, &res, &res, &res, &res, &arg);
271     }
272     return res;
273 }
274 
275 int AlignAndBigLocals(int arg)
276 {
277     puts(__FUNCTION__);
278     int res = 0;
279     __declspec(align(ALIGN)) double d[4];
280     BigObj f1;
281     return TestFunc(1, d, &f1, &res, &res, &res, &res, &res, &arg);
282 }
283 
284 int TryAndAlignAndBigLocals(int arg)
285 {
286     puts(__FUNCTION__);
287     int res = 0;
288     __declspec(align(ALIGN)) double d[4];
289     BigObj f1;
290     try {
291         res = TestFunc(1, d, &f1, &res, &res, &res, &res, &res, &arg);
292     } catch (double) {
293         res = TestFunc(2, d, &f1, &res, &res, &res, &res, &res, &arg);
294     }
295     return res;
296 }
297 
298 int GSCookieAndAlignAndBigLocals(int arg)
299 {
300     puts(__FUNCTION__);
301     int res = 0;
302     char buf[16];
303     __declspec(align(ALIGN)) double d[4];
304     BigObj f1;
305     return TestFunc(1, buf, d, &f1, &res, &res, &res, &res, &res, &arg);
306 }
307 
308 int TryAndGSCookieAndAlignAndBigLocals(int arg)
309 {
310     puts(__FUNCTION__);
311     int res = 0;
312     char buf[16];
313     __declspec(align(ALIGN)) double d[4];
314     BigObj f1;
315     try {
316         res = TestFunc(1, buf, d, &f1, &res, &res, &res, &res, &res, &arg);
317     } catch (double) {
318         res = TestFunc(2, buf, d, &f1, &res, &res, &res, &res, &res, &arg);
319     }
320     return res;
321 }
322 
323 int AllocaAndBigLocals(int arg)
324 {
325     puts(__FUNCTION__);
326     int res = 0;
327     BigObj f1;
328     return TestFunc(1, _alloca(global), &f1, &res, &res, &res, &res, &res, &arg);
329 }
330 
331 int TryAndAllocaAndBigLocals(int arg)
332 {
333     puts(__FUNCTION__);
334     int res = 0;
335     BigObj f1;
336     try {
337         res = TestFunc(1, _alloca(global), &f1, &res, &res, &res, &res, &res, &arg);
338     } catch (double) {
339         res = TestFunc(2, &f1, &res, &res, &res, &res, &res, &arg);
340     }
341     return res;
342 }
343 
344 int GSCookieAndAllocaAndBigLocals(int arg)
345 {
346     puts(__FUNCTION__);
347     int res = 0;
348     char buf[16];
349     BigObj f1;
350     return TestFunc(1, buf, _alloca(global), &f1, &res, &res, &res, &res, &res, &arg);
351 }
352 
353 int TryAndGSCookieAndAllocaAndBigLocals(int arg)
354 {
355     puts(__FUNCTION__);
356     int res = 0;
357     char buf[16];
358     BigObj f1;
359     try {
360         res = TestFunc(1, &buf, _alloca(global), &f1, &res, &res, &res, &res, &res, &arg);
361     } catch (double) {
362         res = TestFunc(2, &buf, &f1, &res, &res, &res, &res, &res, &arg);
363     }
364     return res;
365 }
366 
367 int AlignAndAllocaAndBigLocals(int arg)
368 {
369     puts(__FUNCTION__);
370     int res = 0;
371     __declspec(align(ALIGN)) double d[4];
372     BigObj f1;
373     return TestFunc(1, d, _alloca(global), &f1, &res, &res, &res, &res, &res, &arg);
374 }
375 
376 int TryAndAlignAndAllocaAndBigLocals(int arg)
377 {
378     puts(__FUNCTION__);
379     int res = 0;
380     __declspec(align(ALIGN)) double d[4];
381     BigObj f1;
382     try {
383         res = TestFunc(1, d, _alloca(global), &f1, &res, &res, &res, &res, &res, &arg);
384     } catch (double) {
385         res = TestFunc(2, d, &f1, &res, &res, &res, &res, &res, &arg);
386     }
387     return res;
388 }
389 
390 int GSCookieAndAlignAndAllocaAndBigLocals(int arg)
391 {
392     puts(__FUNCTION__);
393     int res = 0;
394     char buf[16];
395     __declspec(align(ALIGN)) double d[4];
396     BigObj f1;
397     return TestFunc(1, buf, d, _alloca(global), &f1, &res, &res, &res, &res, &res, &arg);
398 }
399 
400 int TryAndGSCookieAndAlignAndAllocaAndBigLocals(int arg)
401 {
402     puts(__FUNCTION__);
403     int res = 0;
404     char buf[16];
405     __declspec(align(ALIGN)) double d[4];
406     BigObj f1;
407     try {
408         res = TestFunc(1, buf, d, _alloca(global), &f1, &res, &res, &res, &res, &res, &arg);
409     } catch (double) {
410         res = TestFunc(2, buf, d, &f1, &res, &res, &res, &res, &res, &arg);
411     }
412     return res;
413 }
414 
415 __declspec(noinline)
416 int TestFunc(int, ...)
417 {
418     if (TestFuncThrows)
419     {
420         TestFuncThrows = false;
421         throw 123;
422     }
423 
424     return global;
425 }
426 
427 void RunTests()
428 {
429     puts("Test pass 1 - no throws");
430 
431     try
432     {
433         Simple(1);
434         Try(1);
435         GSCookie(1);
436         TryAndGSCookie(1);
437         Align(1);
438         TryAndAlign(1);
439         GSCookieAndAlign(1);
440         TryAndGSCookieAndAlign(1);
441         Alloca(1);
442         TryAndAlloca(1);
443         GSCookieAndAlloca(1);
444         TryAndGSCookieAndAlloca(1);
445         AlignAndAlloca(1);
446         TryAndAlignAndAlloca(1);
447         GSCookieAndAlignAndAlloca(1);
448         TryAndGSCookieAndAlignAndAlloca(1);
449         BigLocals(1);
450         TryAndBigLocals(1);
451         GSCookieAndBigLocals(1);
452         TryAndGSCookieAndBigLocals(1);
453         AlignAndBigLocals(1);
454         TryAndAlignAndBigLocals(1);
455         GSCookieAndAlignAndBigLocals(1);
456         TryAndGSCookieAndAlignAndBigLocals(1);
457         AllocaAndBigLocals(1);
458         TryAndAllocaAndBigLocals(1);
459         GSCookieAndAllocaAndBigLocals(1);
460         TryAndGSCookieAndAllocaAndBigLocals(1);
461         AlignAndAllocaAndBigLocals(1);
462         TryAndAlignAndAllocaAndBigLocals(1);
463         GSCookieAndAlignAndAllocaAndBigLocals(1);
464         TryAndGSCookieAndAlignAndAllocaAndBigLocals(1);
465     }
466     catch (...)
467     {
468         puts("ERROR - throw not expected");
469         ++failures;
470     }
471 
472     puts("Test pass 2 - throws");
473 
474     for (int i = 0; i < 32; ++i)
475     {
476         TestFuncThrows = true;
477         bool caught = false;
478         try
479         {
480             switch (i)
481             {
482             case 0: Simple(1); break;
483             case 1: Try(1); break;
484             case 2: GSCookie(1); break;
485             case 3: TryAndGSCookie(1); break;
486             case 4: Align(1); break;
487             case 5: TryAndAlign(1); break;
488             case 6: GSCookieAndAlign(1); break;
489             case 7: TryAndGSCookieAndAlign(1); break;
490             case 8: Alloca(1); break;
491             case 9: TryAndAlloca(1); break;
492             case 10: GSCookieAndAlloca(1); break;
493             case 11: TryAndGSCookieAndAlloca(1); break;
494             case 12: AlignAndAlloca(1); break;
495             case 13: TryAndAlignAndAlloca(1); break;
496             case 14: GSCookieAndAlignAndAlloca(1); break;
497             case 15: TryAndGSCookieAndAlignAndAlloca(1); break;
498             case 16: BigLocals(1); break;
499             case 17: TryAndBigLocals(1); break;
500             case 18: GSCookieAndBigLocals(1); break;
501             case 19: TryAndGSCookieAndBigLocals(1); break;
502             case 20: AlignAndBigLocals(1); break;
503             case 21: TryAndAlignAndBigLocals(1); break;
504             case 22: GSCookieAndAlignAndBigLocals(1); break;
505             case 23: TryAndGSCookieAndAlignAndBigLocals(1); break;
506             case 24: AllocaAndBigLocals(1); break;
507             case 25: TryAndAllocaAndBigLocals(1); break;
508             case 26: GSCookieAndAllocaAndBigLocals(1); break;
509             case 27: TryAndGSCookieAndAllocaAndBigLocals(1); break;
510             case 28: AlignAndAllocaAndBigLocals(1); break;
511             case 29: TryAndAlignAndAllocaAndBigLocals(1); break;
512             case 30: GSCookieAndAlignAndAllocaAndBigLocals(1); break;
513             case 31: TryAndGSCookieAndAlignAndAllocaAndBigLocals(1); break;
514             }
515         }
516         catch (int)
517         {
518             caught = true;
519         }
520 
521         if (!caught)
522         {
523             puts("ERROR - did not catch expected thrown object");
524             ++failures;
525         }
526     }
527 }
528 
529 int main()
530 {
531     __try
532     {
533         RunTests();
534     }
535     __except (1)
536     {
537         puts("ERROR - Unexpectedly caught an exception");
538         ++failures;
539     }
540 
541     if (failures)
542     {
543         printf("Test failed with %d failure%s\n",
544                failures, failures == 1 ? "" : "s");
545     }
546     else
547     {
548         puts("Test passed");
549     }
550 
551     return failures;
552 }
553