Example: sig-handler funcs for C and C++ (throw-catch) PART 1
Posted 05-13-2012 at 11:22 PM by rainbowsally
Today's Features
To compile the C++ example these vars are set in mc2.def and should be similar for other methods of building it.
To compile the C example
So let's first take a peek at the two versions of main for the C and C++ tests. These two versions are mutually exclusive and the makefiles are not the same either. Use whatever tricks you like to symlink or move files as required for the different builds if you want to see them both.
Note: This C++ code is the result of several attempts to get at the low level throw and catch functions (tracing into a debug version of the entire gcc installation) which ended up being much more complicated than this and couldn't be used in C at all.
file: src/main.cpp
See the makefile tips in the next post if you want to build the C++ tests above.
Here's the straight C version. It does have the -std-gnu99 flag set but I don't remember if that's still needed or not as the code has evolved.
file: src/main.c
Cont'd in part 2
- THROW-CATCH in C
- Translating signals to C++ throw-catch parameters.
To compile the C++ example these vars are set in mc2.def and should be similar for other methods of building it.
Code:
COMPILE = g++ -m32 -c -o # COMPILE <output_file> ... CFLAGS = -Wall -g3 --save-temps # or CFLAGS = -Wall -O2 # optimized INCLUDE = -I $(SRCDIR) -I$(PREFIX)/include LINK = g++ -m32 -o # LINK <output_file> ... LDFLAGS = # $(GCCDIR)/libgcc_eh.a LIB = -L/usr/lib -L/opt/gcc-dbg/lib
Code:
COMPILE = gcc -m32 -c -o # COMPILE <output_file> ... CFLAGS = -Wall -g3 -std=gnu99 # --save-temps # or CFLAGS = -Wall -O2 -std=gnu99 # optimized INCLUDE = -I $(SRCDIR) LINK = gcc -m32 -o # LINK <output_file> ... LDFLAGS = # $(GCCDIR)/libgcc_eh.a LIB = -L/usr/lib # -L$(PREFIX)/lib -L/opt/gcc-dbg/lib/
Note: This C++ code is the result of several attempts to get at the low level throw and catch functions (tracing into a debug version of the entire gcc installation) which ended up being much more complicated than this and couldn't be used in C at all.
file: src/main.cpp
Code:
// generic C++ source template created by new.main #include <stdio.h> // printf(), FILE*, etc. #include <malloc.h> // malloc(), free() #include <string.h> // strcpy(), memcpy(), etc. #include <stdlib.h> // exit() #include "signal-handler.h" void dbg(){} // seg fault corrected void test_handled() { printf("Test 1 (handled segfault):\n"); try { PUSH_HANDLER() // set up HANDLE(flg) as the signal hander { char* s = 0; s += 9; int c = *s; c = c; // use it } HANDLE(true); // handle signals and flag = continue normally POP_HANDLER(); // end HANDLER block to continue execution if(throw_code == 11) { // do segfault cleanup if any printf("%s: handling segfault\n", __func__); } else // abort { printf("%s: can't handle signal (%d)\n", __func__, throw_code); exit(throw_code); } } catch(int err) { if(err) throw(err); } } // seg fault uncorrected (fatal) void test_unhandled() { printf("Test 2 (unhandled segfault):\n"); try { PUSH_HANDLER() // set up HANDLE(flg) as the signal hander { char* s = 0; int c = *s; c = c; // use it } HANDLE(false) // handle signals and flag = not continuing { printf("%s: not handling segfault\n", __func__); printf("%s: throwing code (1)\n", __func__); throw(1); } POP_HANDLER(); // end HANDLER block to continue execution } catch(int err) { if(err) throw(err); } } void tester() { printf("%s: testing translating handled and unhandled signals to throw-catch\n", __func__); int caught = 0; try { PUSH_HANDLER() // set up HANDLE(flg) as the signal hander { test_handled(); } HANDLE(false) // handle signals and flag = not continuing { printf("test_handled screwed up, supposed handle errors\n"); printf("%s: HANDLE throwing code (4)\n", __func__); throw(4); } POP_HANDLER(); // end HANDLER block to continue execution } catch(int err) { caught = err; } // caught... try { PUSH_HANDLER() // set up HANDLE(flg) as the signal hander { test_unhandled(); } // this time we want to know if the signal was handled or not HANDLE(false) // handle signals and flag = not continuing { printf("%s: can't handle throw_code = %d\n", __func__, throw_code); printf("%s: HANDLE throwing code (2)\n", __func__); throw(2); } POP_HANDLER(); // end HANDLER block to continue execution } catch(int err) { caught += 2; } if(caught) { printf("%s: caught cumulative error code(s) (%d)\n", __func__, caught); printf("%s: rethrowing throw_code (%d) from handler funcs\n", __func__, throw_code); if(caught) throw(throw_code); } } int main(int argc, char** argv) { dbg(); // done only once in main(); BEGIN_MAIN_HANDLER(); // init system try { PUSH_HANDLER() // set up HANDLE(flg) as the signal hander { tester(); } HANDLE(false) // handle signals and flag = not continuing { throw(1); } POP_HANDLER(); // end HANDLER block to continue execution } catch(int err) { if(err) { printf("main: caught code (%d)\n", err); } } // done only once in main(); END_MAIN_HANDLER(); // reset terminate function for throw-catch printf("Exiting main() normally after testing\n"); return 0; }
Here's the straight C version. It does have the -std-gnu99 flag set but I don't remember if that's still needed or not as the code has evolved.
file: src/main.c
Code:
// main.c sig-handler test /* In the C version to avoid adding an additional PUSH_HANDLER/POP_HANDLER pair around the individual tests, we don't HANDLER_THROW() anything until we leave the block, reading the handler_code to determine whether to throw or not. As a result the HANDLE() functions set the continuing flag to true and 'catch' is simulated by reading the handler_code flag. */ #include <stdio.h> // printf(), FILE*, etc. #include <malloc.h> // malloc(), free() #include <string.h> // strcpy(), memcpy(), etc. #include "signal-handler.h" // these macros help show what the param in HANDLE(param) // is doing. It's only a flag for whether to unnest the // handlers or not within a HANDLE block. True = continue // i.e., NOT to unnest the HANDLER #ifndef true #define true 1 #endif #ifndef false #define false 0 #endif void dbg(){} void noop() {} // seg fault corrected void test_handled() { printf("Test 1 (handled segfault):\n"); PUSH_HANDLER() // set up HANDLE(flg) as the signal hander { char* s = 0; s += 9; int c = *s; c = c; // use it } HANDLE(true); // handle signals and flag = continue normally POP_HANDLER(); // end HANDLER block to continue execution if(throw_code == 11) { // do segfault cleanup if any printf("%s: handling segfault\n", __func__); } else // abort { printf("%s: can't handle signal (%d)\n", __func__, throw_code); exit(throw_code); } if(handler_code) HANDLER_THROW(handler_code); else noop(); } // seg fault uncorrected (fatal) void test_unhandled() { printf("Test 2 (unhandled segfault):\n"); PUSH_HANDLER() // set up HANDLE(flg) as the signal hander { char* s = 0; int c = *s; c = c; // use it } HANDLE(true) // handle signals and flag = continuing { printf("%s: not handling segfault\n", __func__); printf("%s: throwing code (1)\n", __func__); handler_code = 1; } POP_HANDLER(); // end HANDLER block to continue execution if(handler_code) HANDLER_THROW(handler_code); } void tester() { printf("%s: testing translating handled and unhandled signals to throw-catch\n", __func__); int caught = 0; PUSH_HANDLER() // set up HANDLE(flg) as the signal hander { test_handled(); } HANDLE(true) // handle signals and flag = continuing { printf("test_handled screwed up, supposed handle errors\n"); printf("%s: HANDLE throwing code (4)\n", __func__); handler_code = 4; } POP_HANDLER(); // end HANDLER block to continue execution if(handler_code) caught = handler_code; PUSH_HANDLER() // set up HANDLE(flg) as the signal hander { test_unhandled(); } // this time we want to know if the signal was handled or not HANDLE(true) // handle signals and flag = continuing { printf("%s: can't handle throw_code = %d\n", __func__, throw_code); printf("%s: HANDLE throwing code (2)\n", __func__); handler_code = 2; } POP_HANDLER(); // end HANDLER block to continue execution if(handler_code) caught += handler_code; if(caught) { printf("%s: caught cumulative error code(s) (%d)\n", __func__, caught); printf("%s: rethrowing throw_code (%d) from handler funcs\n", __func__, throw_code); HANDLER_THROW(throw_code); } } int main(int argc, char** argv) { dbg(); // done only once in main(); BEGIN_MAIN_HANDLER(); // init system PUSH_HANDLER() // set up HANDLE(flg) as the signal hander { tester(); } HANDLE(true) // handle signals and flag = continuing handler_code = 1; POP_HANDLER(); // end HANDLER block to continue execution // done only once in main(); END_MAIN_HANDLER(); // reset terminate function for throw-catch printf("Exiting main() normally after testing\n"); return 0; }
Total Comments 0