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