// Compile with gcc -Wall -pedantic-errors -std=gnu99 foo.c // #include #include #include // Pointer to functions like void f(void) // typedef void (*Func)(void); // Store where to go when SIGSEGV caught // static sigjmp_buf jumpTarget; // Called when SIGSEGV caught // static void sigHandler(int sig) { siglongjmp(jumpTarget, sig); } // Execute the supplied function, return 0 for success and 1 for SIGSEGV // int catchCrash(Func f) { struct sigaction oldAction; struct sigaction newAction; // Remember the old SIGSEGV handler and set a new handler newAction.sa_flags = 0; newAction.sa_handler = sigHandler; sigemptyset(&newAction.sa_mask); sigaction(SIGSEGV, &newAction, &oldAction); // Crashing code ends up inside this block if ( __extension__ sigsetjmp(jumpTarget, 1) != 0 ) { return 1; // crash detected } // Execute the function: maybe crash, maybe not f(); // Restore the old handler sigaction(SIGSEGV, &oldAction, NULL); return 0; } // Innocuous function // void sayHello(void) { printf("Hello World\n"); } // Attempt to write to address zero // void writeZero(void) { int *p = NULL; *p = 42; } // Attempt to read from address zero // void readZero(void) { int *p = NULL; printf("Read: %d\n", *p); } // Attempt to execute code at address zero // void jmpZero(void) { Func f = NULL; f(); } int main(void) { printf("catchCrash(sayHello) returned %d\n", catchCrash(sayHello)); printf("catchCrash(writeZero) returned %d\n", catchCrash(writeZero)); printf("catchCrash(readZero) returned %d\n", catchCrash(readZero)); printf("catchCrash(jmpZero) returned %d\n", catchCrash(jmpZero)); return 0; }