1 #include "test.h"
2 #include "unwind.h"
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <stdint.h>
6
7 #include <exception>
8
9 #define fprintf(...)
10
log_cleanup(void * ignored)11 void log_cleanup(void* ignored)
12 {
13 //printf("Cleanup called on %s\n", *(char**)ignored);
14 }
15 #define CLEANUP\
16 __attribute__((cleanup(log_cleanup))) __attribute__((unused))\
17 const char *f = __func__;
18
19 /**
20 * Simple struct to test throwing.
21 */
22 struct foo
23 {
24 int i;
25 };
26
27 struct bar : foo
28 {
29 float bar;
30 };
31
32
33 /**
34 * Non-pod type to test throwing
35 */
36 class non_pod {
37 public:
non_pod(int i)38 non_pod(int i): x(i) {}
39 int x;
40 };
41
42
43 static int cleanup_count;
44 /**
45 * Simple structure declared with a destructor. Destroying this object will
46 * increment cleanup count. The destructor should be called automatically if
47 * an instance of cl is allocated with automatic storage.
48 */
49 struct cl
50 {
51 int i;
~clcl52 ~cl() { fprintf(stderr, "cl destroyed: %d\n", i); cleanup_count++; }
53 };
54 /**
55 * Test that one cl was destroyed when running the argument.
56 */
57 #define TEST_CLEANUP(x) do {\
58 int cleanups = cleanup_count;\
59 { x; }\
60 TEST(cleanup_count == cleanups+1, "Cleanup ran correctly");\
61 } while(0)
62
inner(int i)63 int inner(int i)
64 {
65 CLEANUP
66 switch (i)
67 {
68 case 0: throw (int)1.0;
69 case 1: throw (float)1.0;
70 case 2: fprintf(stderr, "Throwing int64_t\n");throw (int64_t)1;
71 case 3: { foo f = {2} ; throw f; }
72 case 4: { bar f; f.i = 2 ; f.bar=1 ; throw f; }
73 case 5: throw non_pod(3);
74 }
75 return -1;
76 }
77
outer(int i)78 int outer(int i) throw(float, int, foo, non_pod)
79 {
80 //CLEANUP
81 inner(i);
82 return 1;
83 }
84
test_const(void)85 static void test_const(void)
86 {
87 int a = 1;
88 try
89 {
90 throw a;
91 }
92 catch (const int b)
93 {
94 TEST(a == b, "Caught int as const int");
95 }
96 catch(...)
97 {
98 TEST(0, "Failed to catch int as const int");
99 }
100 try
101 {
102 throw &a;
103 }
104 catch (const int *b)
105 {
106 TEST(&a == b, "Caught int* as const int*");
107 }
108 catch(...)
109 {
110 TEST(0, "Failed to catch int* as const int*");
111 }
112 }
113
test_catch(int s)114 static void test_catch(int s)
115 {
116 cl c;
117 c.i = 12;
118 fprintf(stderr, "Entering try\n");
119 try
120 {
121 outer(s);
122 }
123 catch(int i)
124 {
125 fprintf(stderr, "Caught int %d in test %d\n", i, s);
126 TEST((s == 0 && i == 1) || (s == 2 && i == 0), "Caught int");
127 return;
128 }
129 catch (float f)
130 {
131 fprintf(stderr, "Caught float %f!\n", f);
132 TEST(s == 1 && f == 1, "Caught float");
133 return;
134 }
135 catch (foo f)
136 {
137 fprintf(stderr, "Caught struct {%d}!\n", f.i);
138 TEST((s == 3 || s == 4) && f.i == 2, "Caught struct");
139 return;
140 }
141 catch (non_pod np) {
142 fprintf(stderr, "Caught non_pod {%d}!\n", np.x);
143 TEST(s == 5 && np.x == 3, "Caught non_pod");
144 return;
145 }
146 //abort();
147 TEST(0, "Unreachable line reached");
148 }
149
test_nested1(void)150 void test_nested1(void)
151 {
152 CLEANUP;
153 cl c;
154 c.i = 123;
155 try
156 {
157 outer(0);
158 }
159 catch (int a)
160 {
161 try
162 {
163 TEST(a == 1, "Caught int");
164 outer(1);
165 }
166 catch (float f)
167 {
168 TEST(f == 1, "Caught float inside outer catch block");
169 throw;
170 }
171 }
172 }
173
test_nested()174 void test_nested()
175 {
176 try
177 {
178 test_nested1();
179 }
180 catch (float f)
181 {
182 fprintf(stderr, "Caught re-thrown float\n");
183 TEST(f == 1, "Caught re-thrown float");
184 }
185 }
186
187 static int violations = 0;
throw_zero()188 static void throw_zero()
189 {
190 violations++;
191 fprintf(stderr, "Throwing 0\n");
192 throw 0;
193 }
194
195 struct uncaught_exception_checker
196 {
uncaught_exception_checkeruncaught_exception_checker197 uncaught_exception_checker(bool uncaught) : m_uncaught(uncaught) {}
~uncaught_exception_checkeruncaught_exception_checker198 ~uncaught_exception_checker() {
199 if (std::uncaught_exception())
200 TEST(m_uncaught, "At least one uncaught exception is in flight");
201 else
202 TEST(!m_uncaught, "No uncaught exceptions are in flight");
203 }
204 bool m_uncaught;
205 };
206
test_rethrown_uncaught_exception()207 void test_rethrown_uncaught_exception()
208 {
209 uncaught_exception_checker outer(false);
210 try
211 {
212 try
213 {
214 throw 42;
215 }
216 catch (int)
217 {
218 uncaught_exception_checker inner(true);
219 throw;
220 }
221 }
222 catch (...) {}
223 }
224
exception_cleanup(_Unwind_Reason_Code,struct _Unwind_Exception * ex)225 static void exception_cleanup(_Unwind_Reason_Code, struct _Unwind_Exception *ex)
226 {
227 delete ex;
228 }
229
test_rethrown_uncaught_foreign_exception()230 void test_rethrown_uncaught_foreign_exception()
231 {
232 uncaught_exception_checker outer(false);
233 try
234 {
235 try
236 {
237 // Throw a foreign exception.
238 _Unwind_Exception *ex = new _Unwind_Exception;
239 ex->exception_class = 1234;
240 ex->exception_cleanup = exception_cleanup;
241 _Unwind_RaiseException(ex);
242 }
243 catch (...)
244 {
245 // Note: Uncaught exceptions doesn't report foreign exceptions,
246 // because we have no way of receiving a report that the other
247 // language has caught it.
248 uncaught_exception_checker inner(false);
249 throw;
250 }
251 }
252 catch (...) {}
253 }
254
255
test_uncaught_exception()256 void test_uncaught_exception()
257 {
258 uncaught_exception_checker outer(false);
259 try {
260 uncaught_exception_checker inner(true);
261 throw 42;
262 }
263 catch (...) {}
264 }
265
266 struct uncaught_exceptions_checker
267 {
uncaught_exceptions_checkeruncaught_exceptions_checker268 uncaught_exceptions_checker(int uncaught) : m_uncaught(uncaught) {}
~uncaught_exceptions_checkeruncaught_exceptions_checker269 ~uncaught_exceptions_checker() {
270 char msg[128];
271 int uncaught = std::uncaught_exceptions();
272 snprintf(msg, sizeof msg, "%d uncaught exception%s in flight",
273 uncaught, uncaught == 1 ? " is" : "s are");
274 TEST(uncaught == m_uncaught, msg);
275 }
276 int m_uncaught;
277 };
278
279 class top {
280 public:
~top()281 ~top() {
282 try {
283 uncaught_exceptions_checker uec(4);
284 throw "top";
285 }
286 catch (...) {}
287 }
288 };
289
290 class middle {
291 public:
~middle()292 ~middle() {
293 try {
294 top f;
295 uncaught_exceptions_checker uec(3);
296 throw "middle";
297 }
298 catch (...) {}
299 }
300 };
301
302 class bottom {
303 public:
~bottom()304 ~bottom() {
305 try {
306 middle f;
307 uncaught_exceptions_checker uec(2);
308 throw "bottom";
309 }
310 catch (...) {}
311 }
312 };
313
test_uncaught_exceptions()314 void test_uncaught_exceptions()
315 {
316 uncaught_exceptions_checker outer(0);
317 try {
318 bottom b;
319 uncaught_exceptions_checker inner(1);
320 throw "test";
321 }
322 catch (...) {}
323 }
324
325 extern "C" void __cxa_bad_cast();
326
test_exceptions(void)327 void test_exceptions(void)
328 {
329 std::set_unexpected(throw_zero);
330 TEST_CLEANUP(test_catch(0));
331 TEST_CLEANUP(test_catch(1));
332 TEST_CLEANUP(test_catch(3));
333 TEST_CLEANUP(test_catch(4));
334 TEST_CLEANUP(test_catch(5));
335 TEST_CLEANUP(test_nested());
336 try{
337 test_catch(2);
338 TEST(violations == 1, "Exactly one exception spec violation");
339 }
340 catch (int64_t i) {
341 TEST(0, "Caught int64_t, but that violates an exception spec");
342 }
343 int a;
344 try {
345 throw &a;
346 }
347 catch (const int *b)
348 {
349 TEST(&a==b, "Caught const int from thrown int");
350 }
351 try {
352 throw &a;
353 }
354 catch (int *b)
355 {
356 TEST(&a==b, "Caught int from thrown int");
357 }
358 try
359 {
360 __cxa_bad_cast();
361 }
362 catch (std::exception b)
363 {
364 TEST(1, "Caught bad cast");
365 }
366 catch (...)
367 {
368 TEST(0, "Bad cast was not caught correctly");
369 }
370 test_const();
371 test_uncaught_exception();
372 test_rethrown_uncaught_exception();
373 test_rethrown_uncaught_foreign_exception();
374 test_uncaught_exceptions();
375
376
377 //printf("Test: %s\n",
378 }
379