// Compile with gcc -Wall -pedantic-errors -std=gnu99 foo.c
//
#include <stdio.h>
#include <setjmp.h>
#include <signal.h>
// 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;
}