summaryrefslogtreecommitdiff
path: root/debug/tst-longjmp_chk2.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2009-07-30 17:48:58 -0700
committerUlrich Drepper <drepper@redhat.com>2009-07-30 17:48:58 -0700
commita9a04420818e1ab0a49838e2eb83ebb66baaeaac (patch)
tree1ecde0b897fecaaf056c3771fe64eeb519e602f3 /debug/tst-longjmp_chk2.c
parent5ead9ce5c788e7dbb0bd01888c4bcb37a8bc2ff1 (diff)
Add test case for ____longjmp_chk vs signal stacks.
Diffstat (limited to 'debug/tst-longjmp_chk2.c')
-rw-r--r--debug/tst-longjmp_chk2.c114
1 files changed, 114 insertions, 0 deletions
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"