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