diff options
Diffstat (limited to 'debug')
-rw-r--r-- | debug/Makefile | 3 | ||||
-rw-r--r-- | debug/tst-longjmp_chk2.c | 114 |
2 files changed, 116 insertions, 1 deletions
diff --git a/debug/Makefile b/debug/Makefile index 181169b90d..99c8092074 100644 --- a/debug/Makefile +++ b/debug/Makefile @@ -118,7 +118,8 @@ LDFLAGS-tst-lfschk6 = -lstdc++ tests = backtrace-tst tst-longjmp_chk tst-chk1 tst-chk2 tst-chk3 \ tst-lfschk1 tst-lfschk2 tst-lfschk3 test-strcpy_chk test-stpcpy_chk \ - tst-chk4 tst-chk5 tst-chk6 tst-lfschk4 tst-lfschk5 tst-lfschk6 + tst-chk4 tst-chk5 tst-chk6 tst-lfschk4 tst-lfschk5 tst-lfschk6 \ + tst-longjmp_chk2 extra-libs = libSegFault libpcprofile extra-libs-others = $(extra-libs) diff --git a/debug/tst-longjmp_chk2.c b/debug/tst-longjmp_chk2.c new file mode 100644 index 0000000000..22d8bf0941 --- /dev/null +++ b/debug/tst-longjmp_chk2.c @@ -0,0 +1,114 @@ +/* Test case mostly written by Paolo Bonzini <pbonzini@redhat.com>. */ +#include <assert.h> +#include <setjmp.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/resource.h> + + +static jmp_buf mainloop; +static sigset_t mainsigset; +static int pass; + + +static void +stackoverflow_handler (int sig) +{ + stack_t altstack; + pass++; + sigaltstack (NULL, &altstack); + /* Using printf is not really kosher in signal handlers but we know + it will work. */ + printf ("%*sin signal handler\n", pass, ""); + if (altstack.ss_flags & SS_ONSTACK) + printf ("%*son alternate stack\n", pass, ""); + siglongjmp (mainloop, pass); +} + + +static volatile int * +recurse_1 (int n, volatile int *p) +{ + if (n >= 0) + *recurse_1 (n + 1, p) += n; + return p; +} + + +static int +recurse (int n) +{ + int sum = 0; + return *recurse_1 (n, &sum); +} + + +static int +do_test (void) +{ + char mystack[SIGSTKSZ]; + stack_t altstack; + struct sigaction action; + sigset_t emptyset; + /* Before starting the endless recursion, try to be friendly to the user's + machine. On some Linux 2.2.x systems, there is no stack limit for user + processes at all. We don't want to kill such systems. */ + struct rlimit rl; + rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */ + setrlimit (RLIMIT_STACK, &rl); + /* Install the alternate stack. */ + altstack.ss_sp = mystack; + altstack.ss_size = sizeof (mystack); + altstack.ss_flags = 0; /* no SS_DISABLE */ + if (sigaltstack (&altstack, NULL) < 0) + { + puts ("first sigaltstack failed"); + return 0; + } + /* Install the SIGSEGV handler. */ + sigemptyset (&action.sa_mask); + action.sa_handler = &stackoverflow_handler; + action.sa_flags = SA_ONSTACK; + sigaction (SIGSEGV, &action, (struct sigaction *) NULL); + sigaction (SIGBUS, &action, (struct sigaction *) NULL); + + /* Save the current signal mask. */ + sigemptyset (&emptyset); + sigprocmask (SIG_BLOCK, &emptyset, &mainsigset); + + /* Provoke two stack overflows in a row. */ + if (sigsetjmp (mainloop, 1) != 0) + { + assert (pass != 0); + printf ("%*sout of signal handler\n", pass, ""); + } + else + assert (pass == 0); + + sigaltstack (NULL, &altstack); + if (altstack.ss_flags & SS_ONSTACK) + printf ("%*son alternate stack\n", pass, ""); + else + printf ("%*snot on alternate stack\n", pass, ""); + + if (pass < 2) + { + recurse (0); + puts ("recurse call returned"); + return 2; + } + + altstack.ss_flags |= SS_DISABLE; + if (sigaltstack (&altstack, NULL) == -1) + printf ("disabling alternate stack failed\n"); + else + printf ("disabling alternate stack succeeded \n"); + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" |