diff --git a/src/regression/sigaltstack.c b/src/regression/sigaltstack.c new file mode 100644 index 0000000..f4ed470 --- /dev/null +++ b/src/regression/sigaltstack.c @@ -0,0 +1,88 @@ +// commit: 6871fd773dcedbf056317d5d5e87b4859e97c4a4 2011-03-10 +// commit: 9505bfbc40fec217820abad7142663eda60cd6be 2014-03-18 +// catching stackoverflow SIGSEGV using sigaltstack +// mips stack_t is inconsistent with other archs +#define _XOPEN_SOURCE 700 +#include +#include +#include +#include +#include +#include "test.h" + +#define T(f) ((f)==0 || (t_error(#f " failed: %s\n", strerror(errno)),0)) + +static char stack[SIGSTKSZ]; +static sigjmp_buf sbuf; +static volatile sig_atomic_t state; + +static void handler(int sig) +{ + uintptr_t i; + stack_t ss; + + if (state!=1) + t_error("handler is not invoked in fillstack (after sigsetjmp returned 0), " + "state is %d, want 1\n", state); + state++; + + i = (uintptr_t)&i; + if (i < (uintptr_t)stack || i >= (uintptr_t)stack+SIGSTKSZ) + t_error("signal handler was not invoked on the altstack\n"); + + T(sigaltstack(0, &ss)); + if (ss.ss_flags != SS_ONSTACK) + t_error("ss_flags is not SS_ONSTACK in the signal handler\n"); + + siglongjmp(sbuf, 1); +} + +static unsigned fillstack(unsigned x) +{ + x++; + if (x==0) { + t_error("wrap around\n"); + return x; + } + return fillstack(fillstack(x)) + 1; +} + +int main(void) +{ + stack_t ss; + struct sigaction sa; + + ss.ss_sp = stack; + ss.ss_size = sizeof stack; + ss.ss_flags = 0; + sa.sa_handler = handler; + sa.sa_flags = SA_ONSTACK; + + T(sigaltstack(&ss, 0)); + T(sigfillset(&sa.sa_mask)); + T(sigaction(SIGSEGV, &sa, 0)); + if (sigsetjmp(sbuf,0) == 0) { + state++; + fillstack(0); + t_error("infinite recursion finished\n"); + } + if (state != 2) + t_error("sigsetjmp returned non-zero before running handler, " + "state is %d, want 2\n", state); + + errno = 0; + ss.ss_size = MINSIGSTKSZ-1; + if (sigaltstack(&ss, 0) != -1 || errno != ENOMEM) + t_error("sigaltstack with stack size < MINSIGSTKSZ should have failed with ENOMEM, " + "got %s\n", strerror(errno)); + errno = 0; + ss.ss_flags = -1; + ss.ss_size = MINSIGSTKSZ; + if (sigaltstack(&ss, 0) != -1 || errno != EINVAL) + t_error("sigaltstack with bad ss_flags should have failed with EINVAL, " + "got %s\n", strerror(errno)); + errno = 0; + T(sigaltstack(0, 0)); + + return t_status; +}