Changeset e4e9173 for doc/working/exception
- Timestamp:
- Jun 13, 2017, 4:24:17 PM (8 years ago)
- Branches:
- ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
- Children:
- 6a48cc9
- Parents:
- 35dd0f42
- Location:
- doc/working/exception/impl
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
doc/working/exception/impl/exception.c
r35dd0f42 re4e9173 22 22 23 23 void __throw_resume(exception except) { 24 void noop() { printf("do nothing\n");} 25 struct __cleanup_hook __blarg __attribute__((cleanup(noop))); 24 25 // DEBUG 26 printf("Throwing resumption exception %d\n", except); 26 27 27 28 struct __try_resume_node * original_head = shared_stack.current_resume; … … 45 46 } 46 47 47 /* __try_resume_node functions:48 * Currently I was planning to generate this code inline, and even if I don't49 * putting it in the header so it can be inlined might be worth while.50 * And if we put them in Cforall code we can use the operators.51 */52 void __try_resume_node_new(struct __try_resume_node * node,53 _Bool (*handler)(exception except)) {54 node->next = shared_stack.top_resume;55 shared_stack.top_resume = node;56 node->try_to_handle = handler;57 }58 59 void __try_resume_node_delete(struct __try_resume_node * node) {60 shared_stack.top_resume = node->next;61 }62 63 48 64 49 // TERMINATION =============================================================== 65 50 66 51 // Requires -fexceptions to work. 52 53 // Global which defines the current exception 54 // Currently an int just to make matching easier 55 //int this_exception; (became shared_stack.current_exception) 56 57 // We need a piece of storage to raise the exception 58 struct _Unwind_Exception this_exception_storage; 59 60 // Function needed by force unwind 61 // It basically says to unwind the whole stack and then exit when we reach the end of the stack 62 static _Unwind_Reason_Code _Stop_Fn( 63 int version, 64 _Unwind_Action actions, 65 _Unwind_Exception_Class exceptionClass, 66 struct _Unwind_Exception * unwind_exception, 67 struct _Unwind_Context * context, 68 void * some_param) { 69 if( actions & _UA_END_OF_STACK ) exit(1); 70 if( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON; 71 72 return _URC_FATAL_PHASE2_ERROR; 73 } 74 75 // Example throw routine 76 void __throw_terminate( int val ) { 77 // Store the current exception 78 shared_stack.current_exception = val; 79 80 // DEBUG 81 printf("Throwing termination exception %d\n", val); 82 83 // Call stdlibc to raise the exception 84 _Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage ); 85 86 // If we reach here it means something happened 87 // For resumption to work we need to find a way to return back to here 88 // Most of them will probably boil down to setting a global flag and making the phase 1 either stop or fail. 89 // Causing an error on purpose may help avoiding unnecessary work but it might have some weird side effects. 90 // If we just pretend no handler was found that would work but may be expensive for no reason since we will always 91 // search the whole stack 92 93 if( ret == _URC_END_OF_STACK ) { 94 // No proper handler was found 95 // This can be handled in several way 96 // C++ calls std::terminate 97 // Here we force unwind the stack, basically raising a cancellation 98 printf("Uncaught exception %p\n", &this_exception_storage); 99 100 ret = _Unwind_ForcedUnwind( &this_exception_storage, _Stop_Fn, (void*)0x22 ); 101 printf("UNWIND ERROR %d after force unwind\n", ret); 102 abort(); 103 } 104 105 // We did not simply reach the end of the stack without finding a handler, 106 // Something wen't wrong 107 printf("UNWIND ERROR %d after raise exception\n", ret); 108 abort(); 109 } 110 111 // This is our personality routine 112 // For every stack frame anotated with ".cfi_personality 0x3,__gcfa_personality_v0" 113 // This function will be called twice when unwinding 114 // Once in the search phased and once in the cleanup phase 115 _Unwind_Reason_Code __gcfa_personality_v0 ( 116 int version, _Unwind_Action actions, unsigned long long exceptionClass, 117 struct _Unwind_Exception* unwind_exception, 118 struct _Unwind_Context* context) 119 { 120 121 // DEBUG 122 //printf("CFA: 0x%lx\n", _Unwind_GetCFA(context)); 123 printf("Personality function (%d, %x, %llu, %p, %p):", version, actions, exceptionClass, unwind_exception, context); 124 125 // If we've reached the end of the stack then there is nothing much we can do... 126 if( actions & _UA_END_OF_STACK ) return _URC_END_OF_STACK; 127 128 // DEBUG 129 if (actions & _UA_SEARCH_PHASE) { 130 printf(" lookup phase"); 131 } 132 // DEBUG 133 else if (actions & _UA_CLEANUP_PHASE) { 134 printf(" cleanup phase"); 135 } 136 // Just in case, probably can't actually happen 137 else { 138 printf(" error\n"); 139 return _URC_FATAL_PHASE1_ERROR; 140 } 141 142 // Get a pointer to the language specific data from which we will read what we need 143 const unsigned char * lsd = (const unsigned char*) _Unwind_GetLanguageSpecificData( context ); 144 145 if( !lsd ) { //Nothing to do, keep unwinding 146 printf(" no LSD"); 147 goto UNWIND; 148 } 149 150 // Get the instuction pointer and a reading pointer into the exception table 151 lsda_header_info lsd_info; 152 const unsigned char * cur_ptr = parse_lsda_header( context, lsd, &lsd_info); 153 _Unwind_Ptr instruction_ptr = _Unwind_GetIP( context ); 154 155 // Linearly search the table for stuff to do 156 while( cur_ptr < lsd_info.action_table ) { 157 _Unwind_Ptr callsite_start; 158 _Unwind_Ptr callsite_len; 159 _Unwind_Ptr callsite_landing_pad; 160 _uleb128_t callsite_action; 161 162 // Decode the common stuff we have in here 163 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_start); 164 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_len); 165 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_landing_pad); 166 cur_ptr = read_uleb128 (cur_ptr, &callsite_action); 167 168 // Have we reach the correct frame info yet? 169 if( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) { 170 //DEBUG BEGIN 171 void * ls = (void*)lsd_info.Start; 172 void * cs = (void*)callsite_start; 173 void * cl = (void*)callsite_len; 174 void * bp = (void*)lsd_info.Start + callsite_start; 175 void * ep = (void*)lsd_info.Start + callsite_start + callsite_len; 176 void * ip = (void*)instruction_ptr; 177 printf("\nfound %p - %p (%p, %p, %p), looking for %p\n", bp, ep, ls, cs, cl, ip); 178 //DEBUG END 179 continue; 180 } 181 182 // Have we gone too far 183 if( lsd_info.Start + callsite_start > instruction_ptr ) { 184 printf(" gone too far"); 185 break; 186 } 187 188 // Something to do? 189 if( callsite_landing_pad ) { 190 // Which phase are we in 191 if (actions & _UA_SEARCH_PHASE) { 192 // Search phase, this means we probably found a potential handler and must check if it is a match 193 194 // If we have arbitrarily decided that 0 means nothing to do and 1 means there is a potential handler 195 // This doesn't seem to conflict the gcc default behavior 196 if (callsite_action != 0) { 197 // Now we want to run some code to see if the handler matches 198 // This is the tricky part where we want to the power to run arbitrary code 199 // However, generating a new exception table entry and try routine every time 200 // is way more expansive than we might like 201 // The information we have is : 202 // - The GR (Series of registers) 203 // GR1=GP Global Pointer of frame ref by context 204 // - The instruction pointer 205 // - The instruction pointer info (???) 206 // - The CFA (Canonical Frame Address) 207 // - The BSP (Probably the base stack pointer) 208 209 210 // The current apprach uses one exception table entry per try block 211 _uleb128_t imatcher; 212 // Get the relative offset to the 213 cur_ptr = read_uleb128 (cur_ptr, &imatcher); 214 215 // Get a function pointer from the relative offset and call it 216 // _Unwind_Reason_Code (*matcher)() = (_Unwind_Reason_Code (*)())lsd_info.LPStart + imatcher; 217 218 _Unwind_Reason_Code (*matcher)() = 219 MATCHER_FROM_CONTEXT(context); 220 int index = matcher(shared_stack.current_exception); 221 _Unwind_Reason_Code ret = (0 == index) 222 ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND; 223 shared_stack.current_handler_index = index; 224 225 226 // Based on the return value, check if we matched the exception 227 if( ret == _URC_HANDLER_FOUND) printf(" handler found\n"); 228 else printf(" no handler\n"); 229 return ret; 230 } 231 232 // This is only a cleanup handler, ignore it 233 printf(" no action"); 234 } 235 else if (actions & _UA_CLEANUP_PHASE) { 236 237 if( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){ 238 // If this is a potential exception handler 239 // but not the one that matched the exception in the seach phase, 240 // just ignore it 241 goto UNWIND; 242 } 243 244 // We need to run some clean-up or a handler 245 // These statment do the right thing but I don't know any specifics at all 246 _Unwind_SetGR( context, __builtin_eh_return_data_regno(0), (_Unwind_Ptr) unwind_exception ); 247 _Unwind_SetGR( context, __builtin_eh_return_data_regno(1), 0 ); 248 249 // I assume this sets the instruction pointer to the adress of the landing pad 250 // It doesn't actually set it, it only state the value that needs to be set once we return _URC_INSTALL_CONTEXT 251 _Unwind_SetIP( context, lsd_info.LPStart + callsite_landing_pad ); 252 253 // DEBUG 254 printf(" action\n"); 255 256 // Return have some action to run 257 return _URC_INSTALL_CONTEXT; 258 } 259 } 260 261 // Nothing to do, move along 262 printf(" no landing pad"); 263 } 264 // No handling found 265 printf(" table end reached\n"); 266 267 // DEBUG 268 UNWIND: 269 printf(" unwind\n"); 270 271 // Keep unwinding the stack 272 return _URC_CONTINUE_UNWIND; 273 } 67 274 68 275 // Try statements are hoisted out see comments for details … … 141 348 " .size __try_terminate, .-__try_terminate\n" 142 349 " .ident \"GCC: (Ubuntu 6.2.0-3ubuntu11~16.04) 6.2.0 20160901\"\n" 143 " .section .note.GNU-stack,\"x\",@progbits\n"350 // " .section .note.GNU-stack,\"x\",@progbits\n" 144 351 ); 145 146 // Global which defines the current exception147 // Currently an int just to make matching easier148 int this_exception;149 150 // We need a piece of storage to raise the exception151 struct _Unwind_Exception this_exception_storage;152 153 // Function needed by force unwind154 // It basically says to unwind the whole stack and then exit when we reach the end of the stack155 static _Unwind_Reason_Code _Stop_Fn(156 int version,157 _Unwind_Action actions,158 _Unwind_Exception_Class exceptionClass,159 struct _Unwind_Exception * unwind_exception,160 struct _Unwind_Context * context,161 void * some_param) {162 if( actions & _UA_END_OF_STACK ) exit(1);163 if( actions & _UA_CLEANUP_PHASE ) return _URC_NO_REASON;164 165 return _URC_FATAL_PHASE2_ERROR;166 }167 168 // Example throw routine169 void __throw_terminate( int val ) {170 // Store the current exception171 this_exception = val;172 173 // DEBUG174 printf("Throwing exception %d\n", this_exception);175 176 // Call stdlibc to raise the exception177 _Unwind_Reason_Code ret = _Unwind_RaiseException( &this_exception_storage );178 179 // If we reach here it means something happened180 // For resumption to work we need to find a way to return back to here181 // Most of them will probably boil down to setting a global flag and making the phase 1 either stop or fail.182 // Causing an error on purpose may help avoiding unnecessary work but it might have some weird side effects.183 // If we just pretend no handler was found that would work but may be expensive for no reason since we will always184 // search the whole stack185 186 if( ret == _URC_END_OF_STACK ) {187 // No proper handler was found188 // This can be handled in several way189 // C++ calls std::terminate190 // Here we force unwind the stack, basically raising a cancellation191 printf("Uncaught exception %p\n", &this_exception_storage);192 193 ret = _Unwind_ForcedUnwind( &this_exception_storage, _Stop_Fn, (void*)0x22 );194 printf("UNWIND ERROR %d after force unwind\n", ret);195 abort();196 }197 198 // We did not simply reach the end of the stack without finding a handler,199 // Something wen't wrong200 printf("UNWIND ERROR %d after raise exception\n", ret);201 abort();202 }203 204 // This is our personality routine205 // For every stack frame anotated with ".cfi_personality 0x3,__gcfa_personality_v0"206 // This function will be called twice when unwinding207 // Once in the search phased and once in the cleanup phase208 _Unwind_Reason_Code __gcfa_personality_v0 (209 int version, _Unwind_Action actions, unsigned long long exceptionClass,210 struct _Unwind_Exception* unwind_exception,211 struct _Unwind_Context* context)212 {213 printf("CFA: 0x%lx\n", _Unwind_GetCFA(context));214 215 // DEBUG216 printf("Personality function (%d, %x, %llu, %p, %p):", version, actions, exceptionClass, unwind_exception, context);217 218 // If we've reached the end of the stack then there is nothing much we can do...219 if( actions & _UA_END_OF_STACK ) return _URC_END_OF_STACK;220 221 // DEBUG222 if (actions & _UA_SEARCH_PHASE) {223 printf(" lookup phase");224 }225 // DEBUG226 else if (actions & _UA_CLEANUP_PHASE) {227 printf(" cleanup phase");228 }229 // Just in case, probably can't actually happen230 else {231 printf(" error\n");232 return _URC_FATAL_PHASE1_ERROR;233 }234 235 // Get a pointer to the language specific data from which we will read what we need236 const unsigned char * lsd = (const unsigned char*) _Unwind_GetLanguageSpecificData( context );237 238 if( !lsd ) { //Nothing to do, keep unwinding239 printf(" no LSD");240 goto UNWIND;241 }242 243 // Get the instuction pointer and a reading pointer into the exception table244 lsda_header_info lsd_info;245 const unsigned char * cur_ptr = parse_lsda_header( context, lsd, &lsd_info);246 _Unwind_Ptr instruction_ptr = _Unwind_GetIP( context );247 248 // Linearly search the table for stuff to do249 while( cur_ptr < lsd_info.action_table ) {250 _Unwind_Ptr callsite_start;251 _Unwind_Ptr callsite_len;252 _Unwind_Ptr callsite_landing_pad;253 _uleb128_t callsite_action;254 255 // Decode the common stuff we have in here256 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_start);257 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_len);258 cur_ptr = read_encoded_value (0, lsd_info.call_site_encoding, cur_ptr, &callsite_landing_pad);259 cur_ptr = read_uleb128 (cur_ptr, &callsite_action);260 261 // Have we reach the correct frame info yet?262 if( lsd_info.Start + callsite_start + callsite_len < instruction_ptr ) {263 //DEBUG BEGIN264 void * ls = (void*)lsd_info.Start;265 void * cs = (void*)callsite_start;266 void * cl = (void*)callsite_len;267 void * bp = (void*)lsd_info.Start + callsite_start;268 void * ep = (void*)lsd_info.Start + callsite_start + callsite_len;269 void * ip = (void*)instruction_ptr;270 printf("\nfound %p - %p (%p, %p, %p), looking for %p\n", bp, ep, ls, cs, cl, ip);271 //DEBUG END272 continue;273 }274 275 // Have we gone too far276 if( lsd_info.Start + callsite_start > instruction_ptr ) {277 printf(" gone too far");278 break;279 }280 281 // Something to do?282 if( callsite_landing_pad ) {283 // Which phase are we in284 if (actions & _UA_SEARCH_PHASE) {285 // Search phase, this means we probably found a potential handler and must check if it is a match286 287 // If we have arbitrarily decided that 0 means nothing to do and 1 means there is a potential handler288 // This doesn't seem to conflict the gcc default behavior289 if (callsite_action != 0) {290 // Now we want to run some code to see if the handler matches291 // This is the tricky part where we want to the power to run arbitrary code292 // However, generating a new exception table entry and try routine every time293 // is way more expansive than we might like294 // The information we have is :295 // - The GR (Series of registers)296 // GR1=GP Global Pointer of frame ref by context297 // - The instruction pointer298 // - The instruction pointer info (???)299 // - The CFA (Canonical Frame Address)300 // - The BSP (Probably the base stack pointer)301 302 303 // The current apprach uses one exception table entry per try block304 _uleb128_t imatcher;305 // Get the relative offset to the306 cur_ptr = read_uleb128 (cur_ptr, &imatcher);307 308 // Get a function pointer from the relative offset and call it309 // _Unwind_Reason_Code (*matcher)() = (_Unwind_Reason_Code (*)())lsd_info.LPStart + imatcher;310 311 _Unwind_Reason_Code (*matcher)() =312 MATCHER_FROM_CONTEXT(context);313 int index = matcher(shared_stack.current_exception);314 _Unwind_Reason_Code ret = (0 == index)315 ? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND;316 shared_stack.current_handler_index = index;317 318 319 // Based on the return value, check if we matched the exception320 if( ret == _URC_HANDLER_FOUND) printf(" handler found\n");321 else printf(" no handler\n");322 return ret;323 }324 325 // This is only a cleanup handler, ignore it326 printf(" no action");327 }328 else if (actions & _UA_CLEANUP_PHASE) {329 330 if( (callsite_action != 0) && !(actions & _UA_HANDLER_FRAME) ){331 // If this is a potential exception handler332 // but not the one that matched the exception in the seach phase,333 // just ignore it334 goto UNWIND;335 }336 337 // We need to run some clean-up or a handler338 // These statment do the right thing but I don't know any specifics at all339 _Unwind_SetGR( context, __builtin_eh_return_data_regno(0), (_Unwind_Ptr) unwind_exception );340 _Unwind_SetGR( context, __builtin_eh_return_data_regno(1), 0 );341 342 // I assume this sets the instruction pointer to the adress of the landing pad343 // It doesn't actually set it, it only state the value that needs to be set once we return _URC_INSTALL_CONTEXT344 _Unwind_SetIP( context, lsd_info.LPStart + callsite_landing_pad );345 346 // DEBUG347 printf(" action\n");348 349 // Return have some action to run350 return _URC_INSTALL_CONTEXT;351 }352 }353 354 // Nothing to do, move along355 printf(" no landing pad");356 }357 // No handling found358 printf(" table end reached\n");359 360 // DEBUG361 UNWIND:362 printf(" unwind\n");363 364 // Keep unwinding the stack365 return _URC_CONTINUE_UNWIND;366 } -
doc/working/exception/impl/exception.h
r35dd0f42 re4e9173 32 32 }; 33 33 34 extern struct shared_stack_t s tared_stack;34 extern struct shared_stack_t shared_stack; -
doc/working/exception/impl/test-main.c
r35dd0f42 re4e9173 1 1 #include "exception.h" 2 2 3 // Use: gcc -fexceptions -Wall -Werror -g exception.c test-main.c 4 3 5 #include <stdio.h> 6 #include <stdbool.h> 4 7 5 8 // Translation Helpers: … … 7 10 struct __cleanup_hook __hidden_hook __attribute__((cleanup(function))) 8 11 12 void __try_resume_node_new(struct __try_resume_node * node, 13 _Bool (*handler)(exception except)) { 14 node->next = shared_stack.top_resume; 15 shared_stack.top_resume = node; 16 node->try_to_handle = handler; 17 } 18 19 void __try_resume_node_delete(struct __try_resume_node * node) { 20 shared_stack.top_resume = node->next; 21 } 9 22 10 23 // Local Print On Exit: … … 19 32 #define raii_t __attribute__((cleanup(raii_dtor))) struct raii_base_type 20 33 34 // =========================================================================== 21 35 // Runtime code (post-translation). 22 36 void terminate(int except_value) { … … 34 48 // Termination Test: Two handlers: no catch, catch 35 49 void bar() { 36 void bar_try1() { 37 terminate(4); 50 raii_t a = {"bar function"}; 51 { 52 void bar_try1() { 53 terminate(4); 54 } 55 void bar_catch1(int index, exception except) { 56 switch(except) { 57 case 1: 58 printf("bar caught exception 3.\n"); 59 break; 60 default: 61 printf("INVALID INDEX in bar: %d (%d)\n", index, except); 62 } 63 } 64 int bar_match1(exception except) { 65 if (3 == except) { 66 return 1; 67 } else { 68 return 0; 69 } 70 } 71 __try_terminate(bar_try1, bar_catch1, bar_match1); 38 72 } 39 void bar_catch1(int index, exception except) {40 switch(except) {41 case 1:42 printf("bar caught exception.\n");43 break;44 default:45 printf("INVALID INDEX in bar: %d\n", except);46 }47 }48 int bar_match1(exception except) {49 if (3 == except) {50 return 1;51 } else {52 return 0;53 }54 }55 __try_terminate(bar_try1, bar_catch1, bar_match1);56 73 } 57 74 58 75 void foo() { 59 void foo_try1() { 60 bar(); 76 raii_t a = {"foo function"}; 77 { 78 void foo_try1() { 79 bar(); 80 } 81 void foo_catch1(int index, exception except) { 82 switch(index) { 83 case 1: 84 printf("foo caught exception 4.\n"); 85 break; 86 case 2: 87 printf("foo caught exception 2.\n"); 88 break; 89 default: 90 printf("INVALID INDEX in foo: %d (%d)\n", index, except); 91 } 92 } 93 int foo_match1(exception except) { 94 if (4 == except) { 95 return 1; 96 } else if (2 == except) { 97 return 2; 98 } else { 99 return 0; 100 } 101 } 102 __try_terminate(foo_try1, foo_catch1, foo_match1); 61 103 } 62 void foo_catch1(int index, exception except) { 63 switch(except) { 64 case 1: 65 printf("foo caught exception 4.\n"); 66 break; 67 case 2: 68 printf("foo caught exception 2.\n"); 69 break; 70 default: 71 printf("INVALID INDEX in foo: %d\n", except); 104 } 105 106 // Resumption Two Handler Test: no catch, catch. 107 void beta() { 108 raii_t a = {"beta function"}; 109 { 110 bool beta_handle1(exception except) { 111 if (3 == except) { 112 printf("beta caught exception 3\n"); 113 return true; 114 } else { 115 return false; 116 } 117 } 118 struct __try_resume_node node 119 __attribute__((cleanup(__try_resume_node_delete))); 120 __try_resume_node_new(&node, beta_handle1); 121 { 122 resume(4); 72 123 } 73 124 } 74 int foo_match1(exception except) { 75 if (4 == except) { 76 return 1; 77 } else if (2 == except) { 78 return 2; 79 } else { 80 return 0; 125 } 126 void alpha() { 127 raii_t a = {"alpha function"}; 128 { 129 bool alpha_handle1(exception except) { 130 if (2 == except) { 131 printf("alpha caught exception 2\n"); 132 return true; 133 } else if (4 == except) { 134 printf("alpha caught exception 4\n"); 135 return true; 136 } else { 137 return false; 138 } 139 } 140 struct __try_resume_node node 141 __attribute__((cleanup(__try_resume_node_delete))); 142 __try_resume_node_new(&node, alpha_handle1); 143 { 144 beta(); 81 145 } 82 146 } 83 __try_terminate(foo_try1, foo_catch1, foo_match1);84 147 } 85 148 149 // Finally Test: 150 void farewell() { 151 { 152 void farewell_finally1() { 153 printf("See you next time\n"); 154 } 155 CLEANUP(farewell_finally1); 156 { 157 printf("jump out of farewell\n"); 158 } 159 } 160 } 161 162 // Resume-to-Terminate Test: 163 void fallback() { 164 //raii_t a = {"fallback function\n"}; 165 { 166 void fallback_try1() { 167 resume(1); 168 } 169 void fallback_catch1(int index, exception except) { 170 switch (index) { 171 case 1: 172 printf("fallback caught termination 1\n"); 173 break; 174 default: 175 printf("INVALID INDEX in fallback: %d (%d)\n", index, except); 176 } 177 } 178 int fallback_match1(exception except) { 179 if (1 == except) { 180 return 1; 181 } else { 182 return 0; 183 } 184 } 185 __try_terminate(fallback_try1, fallback_catch1, fallback_match1); 186 } 187 } 188 189 // main: choose which tests to run 86 190 int main(int argc, char * argv[]) { 87 191 raii_t a = {"main function"}; 88 192 89 foo(); 193 foo(); printf("\n"); 194 alpha(); printf("\n"); 195 farewell(); printf("\n"); 196 fallback(); printf("\n"); 197 // Uncaught termination test. 198 terminate(7); 90 199 }
Note: See TracChangeset
for help on using the changeset viewer.