#include #include #include #include #include #include #include #include #include #include #include int stack_direction; char *stack_bottom; sigjmp_buf return_to_command_loop; NT_TIB *tib; MEMORY_BASIC_INFORMATION m; /* Attempt to recover from SIGSEGV caused by C stack overflow. */ static void handle_sigsegv (int sig, siginfo_t *siginfo, void *arg) { struct rlimit rlim; int fp = open ("sigalt.out", O_CREAT | O_TRUNC | O_WRONLY, 0644); if (fp < 0) perror ("open"); else { write (fp, "ping\n", 5); close (fp); } 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 () { int status; char stack_bottom_variable; /* Record (approximately) where the stack begins. */ stack_bottom = &stack_bottom_variable; tib = (NT_TIB *) __readfsdword(PcTeb); VirtualQuery (stack_bottom, &m, sizeof m); init_sigsegv (); if (!sigsetjmp (return_to_command_loop, 1)) { printf ("command loop 1 before crash\n"); foo (); } else { printf ("command loop 1 after crash\n"); switch (fork ()) { case -1: perror ("fork"); break; case 0: printf ("In child\n"); exit (0); default: wait (&status); printf ("In parent\n"); break; } } if (!sigsetjmp (return_to_command_loop, 1)) { printf ("command loop 2 before crash\n"); foo (); } else { printf ("command loop 2 after crash\n"); switch (fork ()) { case -1: perror ("fork"); break; case 0: printf ("In child\n"); exit (0); default: wait (&status); printf ("In parent\n"); break; } } return 0; }