xref: /netbsd-src/external/bsd/libc++/dist/libcxxrt/test/test_exception.cc (revision ef049e9fc7d6ec4aea42661cf846dcc0a5d0c1fe)
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