I had a need for a try/catch in C. So I wrote a sample program to demo try/catch using some more esoteric functions in the C language. The main functions that do the heavy lifting are:
siglongjmp()
and
sigsetjmp()
and setting signal handlers for
sigaction(SIGBUS, &handle, NULL); sigaction(SIGSEGV, &handle, NULL);
One run:
$ time ./a.out
Bus error
real 0m3.061s
user 0m0.730s
sys 0m1.000s
This is 1,000,000 tries with 1000 bad references interspaced between things.
The Bus error is a normal error that I do _not_ catch. I want to let
normal bad things still happen, I only catch the things that are being
"tried".
This works on mac os x, will try it out on the linux box tonight.
Funny thing, this doesn't catch SIGSEGV on the mac when compiled with
optimizations. Don't know why yet.
So, for right now, this may be suitable for putting into the debug build.
*** Revised ***
I added the volatile keyword in for the local variables in tryvar()
and the optimized version was fixed on mac.
When optimized the code ran like this on the mac:
engr-221:~/projects/improved/CatchMemException jrogers$ time ./a.out
Bus error
real 0m2.783s
user 0m0.870s
sys 0m1.060s
The Linux version runs 10 times faster on an Athlon XP 2100
The program follows:
/* * Test the procedure to catch a memory exception */ #include <sys wait.h> #include <errno.h> #include <fcntl.h> #include <ctype.h> #include <stdio.h> #include <signal.h> #include <setjmp.h> int violation = 0; int try = 0; sigjmp_buf env; /* * Handle the SIGSEGV signal when a memory segmentation error occurs. */ void handle_segfault() { if (try) { /* when we are in a try do this when there is a memory fault */ violation = 1; siglongjmp(env, 1); } else { /* restore normal signal handling if we run into an issue outside of a try */ struct sigaction handle; handle.sa_flags = NULL; handle.sa_handler = NULL; sigaction(SIGBUS, &handle, NULL); sigaction(SIGSEGV, &handle, NULL); } } /* * Check the given memory allocation * Trap any segmentation faults * Return 1 if would have crashed * Return 0 if good. */ int tryvar (void * test){ volatile char x; volatile char * vtest; vtest = (char *) test; try = 1; x = sigsetjmp(env,1); if (x == 0) x = (char) *vtest; x = violation; violation = 0; try = 0; return x; } /* * Initialize the signal handlers for memory faults */ void InitializeSignalHandlers(){ struct sigaction handle; handle.sa_flags = SA_SIGINFO; handle.sa_handler = handle_segfault; sigaction(SIGBUS, &handle, NULL); sigaction(SIGSEGV, &handle, NULL); } /* * Initialize everything and run the tests. */ int main (){ void * test; int * vtest; int a, b, x; test = 0; vtest = (int *)test; InitializeSignalHandlers(); for (b=0; b< 1000; b++){ for (a=0; a< 1000; a++){ if (tryvar (&a)){ printf("a\n"); } else { } } if (tryvar (test)){ } else { printf("b\n"); } } /* Cause a bus error */ x = (int) *vtest; printf("%d\n", x); return 0; }
No comments:
Post a Comment