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 11void 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 */ 22struct foo 23{ 24 int i; 25}; 26 27struct bar : foo 28{ 29 float bar; 30}; 31 32 33/** 34 * Non-pod type to test throwing 35 */ 36class non_pod { 37public: 38 non_pod(int i): x(i) {} 39 int x; 40}; 41 42 43static 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 */ 49struct cl 50{ 51 int i; 52 ~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 63int 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 78int outer(int i) throw(float, int, foo, non_pod) 79{ 80 //CLEANUP 81 inner(i); 82 return 1; 83} 84 85static 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 114static 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 150void 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 174void 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 187static int violations = 0; 188static void throw_zero() 189{ 190 violations++; 191 fprintf(stderr, "Throwing 0\n"); 192 throw 0; 193} 194 195struct uncaught_exception_checker 196{ 197 uncaught_exception_checker(bool uncaught) : m_uncaught(uncaught) {} 198 ~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 207void 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 225static void exception_cleanup(_Unwind_Reason_Code, struct _Unwind_Exception *ex) 226{ 227 delete ex; 228} 229 230void 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 256void 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 266struct uncaught_exceptions_checker 267{ 268 uncaught_exceptions_checker(int uncaught) : m_uncaught(uncaught) {} 269 ~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 279class top { 280public: 281 ~top() { 282 try { 283 uncaught_exceptions_checker uec(4); 284 throw "top"; 285 } 286 catch (...) {} 287 } 288}; 289 290class middle { 291public: 292 ~middle() { 293 try { 294 top f; 295 uncaught_exceptions_checker uec(3); 296 throw "middle"; 297 } 298 catch (...) {} 299 } 300}; 301 302class bottom { 303public: 304 ~bottom() { 305 try { 306 middle f; 307 uncaught_exceptions_checker uec(2); 308 throw "bottom"; 309 } 310 catch (...) {} 311 } 312}; 313 314void 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 325extern "C" void __cxa_bad_cast(); 326 327void 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