115 lines
2.7 KiB
C
115 lines
2.7 KiB
C
|
/* 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"
|