1*fe36f081STimo Kreuzer // Copyright (c) Microsoft. All rights reserved.
2*fe36f081STimo Kreuzer // Licensed under the MIT license. See LICENSE file in the project root for
3*fe36f081STimo Kreuzer // full license information.
4*fe36f081STimo Kreuzer 
5*fe36f081STimo Kreuzer /*
6*fe36f081STimo Kreuzer ** The first call to Test checks to make sure that we don't call terminate
7*fe36f081STimo Kreuzer ** when an SEH fault is triggered. After catching the SEH fault, we then
8*fe36f081STimo Kreuzer ** cause a C++ EH fault (where the destructed object is in the try-block
9*fe36f081STimo Kreuzer ** that threw the exception). The C++ EH fault in the dtor should cause
10*fe36f081STimo Kreuzer ** a call to terminate(); in this case, we register our own handler to
11*fe36f081STimo Kreuzer ** trap the call to terminate(). We then run a second C++ EH fault (where
12*fe36f081STimo Kreuzer ** the destructed object is higher in the call tree than where the
13*fe36f081STimo Kreuzer ** exception was thrown). We trap this call to terminate() as well (with
14*fe36f081STimo Kreuzer ** a different handler) and then exit.
15*fe36f081STimo Kreuzer */
16*fe36f081STimo Kreuzer 
17*fe36f081STimo Kreuzer #include <stdio.h>
18*fe36f081STimo Kreuzer #include <stdlib.h>
19*fe36f081STimo Kreuzer #include <eh.h>
20*fe36f081STimo Kreuzer 
21*fe36f081STimo Kreuzer int FGenSEHException;
22*fe36f081STimo Kreuzer 
23*fe36f081STimo Kreuzer class C
24*fe36f081STimo Kreuzer {
25*fe36f081STimo Kreuzer public:
C()26*fe36f081STimo Kreuzer     C() {}
~C()27*fe36f081STimo Kreuzer     ~C()
28*fe36f081STimo Kreuzer     {
29*fe36f081STimo Kreuzer         printf( "in C::~C()\n");
30*fe36f081STimo Kreuzer         if (FGenSEHException)
31*fe36f081STimo Kreuzer         {
32*fe36f081STimo Kreuzer             printf("generating access violation (SEH)\n");
33*fe36f081STimo Kreuzer             *(volatile char*)(0) = 0; // Uh, EHa, don't you think?
34*fe36f081STimo Kreuzer         }
35*fe36f081STimo Kreuzer         else
36*fe36f081STimo Kreuzer         {
37*fe36f081STimo Kreuzer             printf("throwing C++ exception\n");
38*fe36f081STimo Kreuzer             throw 'a';
39*fe36f081STimo Kreuzer         }
40*fe36f081STimo Kreuzer     }
41*fe36f081STimo Kreuzer };
42*fe36f081STimo Kreuzer 
Test()43*fe36f081STimo Kreuzer int Test()
44*fe36f081STimo Kreuzer {
45*fe36f081STimo Kreuzer     try
46*fe36f081STimo Kreuzer     {
47*fe36f081STimo Kreuzer         C c;
48*fe36f081STimo Kreuzer         throw 1;
49*fe36f081STimo Kreuzer     }
50*fe36f081STimo Kreuzer     catch (int)
51*fe36f081STimo Kreuzer     {
52*fe36f081STimo Kreuzer         printf("Destructor was not invoked \n");
53*fe36f081STimo Kreuzer     }
54*fe36f081STimo Kreuzer     catch (char)
55*fe36f081STimo Kreuzer     {
56*fe36f081STimo Kreuzer         printf("Destructor exited using an exception\n");
57*fe36f081STimo Kreuzer     }
58*fe36f081STimo Kreuzer #if 0
59*fe36f081STimo Kreuzer     catch (...)
60*fe36f081STimo Kreuzer     {
61*fe36f081STimo Kreuzer         printf("Throw caught by wrong handler\n");
62*fe36f081STimo Kreuzer     }
63*fe36f081STimo Kreuzer #endif
64*fe36f081STimo Kreuzer 
65*fe36f081STimo Kreuzer     printf("terminate() was not called\n");
66*fe36f081STimo Kreuzer 
67*fe36f081STimo Kreuzer     return 1;
68*fe36f081STimo Kreuzer }
69*fe36f081STimo Kreuzer 
Bar(void)70*fe36f081STimo Kreuzer void Bar(void)
71*fe36f081STimo Kreuzer {
72*fe36f081STimo Kreuzer     printf("in %s\n", __FUNCTION__);
73*fe36f081STimo Kreuzer     throw 1;
74*fe36f081STimo Kreuzer }
75*fe36f081STimo Kreuzer 
Test2(void)76*fe36f081STimo Kreuzer void Test2(void)
77*fe36f081STimo Kreuzer {
78*fe36f081STimo Kreuzer     printf("in %s\n", __FUNCTION__);
79*fe36f081STimo Kreuzer     C c;
80*fe36f081STimo Kreuzer     Bar();
81*fe36f081STimo Kreuzer     return;
82*fe36f081STimo Kreuzer }
83*fe36f081STimo Kreuzer 
Terminate2(void)84*fe36f081STimo Kreuzer void __cdecl Terminate2(void)
85*fe36f081STimo Kreuzer {
86*fe36f081STimo Kreuzer     printf("termination handler (%s) called\n", __FUNCTION__);
87*fe36f081STimo Kreuzer     exit(0);
88*fe36f081STimo Kreuzer }
89*fe36f081STimo Kreuzer 
Terminate1(void)90*fe36f081STimo Kreuzer void __cdecl Terminate1(void)
91*fe36f081STimo Kreuzer {
92*fe36f081STimo Kreuzer     printf("termination handler (%s) called\n", __FUNCTION__);
93*fe36f081STimo Kreuzer 
94*fe36f081STimo Kreuzer     // Set a new handler and run a second C++ EH test case.
95*fe36f081STimo Kreuzer     set_terminate(Terminate2);
96*fe36f081STimo Kreuzer     Test2();
97*fe36f081STimo Kreuzer     exit(0);
98*fe36f081STimo Kreuzer }
99*fe36f081STimo Kreuzer 
main(void)100*fe36f081STimo Kreuzer int main(void)
101*fe36f081STimo Kreuzer {
102*fe36f081STimo Kreuzer     int i;
103*fe36f081STimo Kreuzer 
104*fe36f081STimo Kreuzer     // First check that we don't terminate on an SEH exception
105*fe36f081STimo Kreuzer     FGenSEHException = 1;
106*fe36f081STimo Kreuzer     __try
107*fe36f081STimo Kreuzer     {
108*fe36f081STimo Kreuzer         i = Test();
109*fe36f081STimo Kreuzer     }
110*fe36f081STimo Kreuzer     __except (1)
111*fe36f081STimo Kreuzer     {
112*fe36f081STimo Kreuzer         printf("caught SEH exception in %s\n", __FUNCTION__);
113*fe36f081STimo Kreuzer     }
114*fe36f081STimo Kreuzer 
115*fe36f081STimo Kreuzer     // Now set our own terminate handler and throw a C++ EH exception
116*fe36f081STimo Kreuzer     set_terminate(Terminate1);
117*fe36f081STimo Kreuzer     FGenSEHException = 0;
118*fe36f081STimo Kreuzer     i = Test();
119*fe36f081STimo Kreuzer 
120*fe36f081STimo Kreuzer     // Should never get here
121*fe36f081STimo Kreuzer     printf("termination handler not called\n");
122*fe36f081STimo Kreuzer     return i;
123*fe36f081STimo Kreuzer }
124