#include #include #include #include #include #include #include int stack_direction; char *stack_bottom; sigjmp_buf return_to_command_loop; /* Attempt to recover from SIGSEGV caused by C stack overflow. */ static void handle_sigsegv (int sig, siginfo_t *siginfo, void *arg) { struct rlimit rlim; if (!getrlimit (RLIMIT_STACK, &rlim)) { enum { STACK_DANGER_ZONE = 32 * 1024 }; char *beg, *end, *addr; beg = stack_bottom; end = stack_bottom + stack_direction * rlim.rlim_cur; if (beg > end) addr = beg, beg = end, end = addr; addr = (char *) siginfo->si_addr; /* If we're somewhere on stack and too close to one of its boundaries, most likely this is it. */ if (beg < addr && addr < end && (addr - beg < STACK_DANGER_ZONE || end - addr < STACK_DANGER_ZONE)) siglongjmp (return_to_command_loop, 1); } /* Otherwise we can't do anything with this. */ abort (); } static int init_sigsegv (void) { struct sigaction sa; stack_t ss; stack_direction = ((char *) &ss < stack_bottom) ? -1 : 1; ss.ss_sp = malloc (SIGSTKSZ); ss.ss_size = SIGSTKSZ; ss.ss_flags = 0; if (sigaltstack (&ss, NULL) < 0) return 0; sigfillset (&sa.sa_mask); sa.sa_sigaction = handle_sigsegv; sa.sa_flags = SA_SIGINFO | SA_ONSTACK; return sigaction (SIGSEGV, &sa, NULL) < 0 ? 0 : 1; } void foo () { int buf[512]; foo (); } int main () { char stack_bottom_variable; /* Record (approximately) where the stack begins. */ stack_bottom = &stack_bottom_variable; init_sigsegv (); if (!sigsetjmp (return_to_command_loop, 1)) { printf ("command loop before crash\n"); foo (); } else printf ("command loop after crash\n"); return 0; }