This is the mail archive of the
java-discuss@sourceware.cygnus.com
mailing list for the Java project.
Re: stack overflow
- To: per at bothner dot com (Per Bothner)
- Subject: Re: stack overflow
- From: Godmar Back <gback at cs dot utah dot edu>
- Date: Mon, 1 Nov 1999 11:40:45 -0700 (MST)
- Cc: gback at cs dot utah dot edu, per at bothner dot com, java-discuss at sourceware dot cygnus dot com
>
> I'm sure it can be implemented portably. I don't know about
> portably *and* efficiently. I also don't know (remember) anything
> about the Gcc implementation, and how general/robust it is.
>
In case anybody is interested, here's my test program for the sparc.
It tests whether we can recover from a segfault taken on an alternate
stack.
It works if the SIGSEGV is caused by a null pointer access.
It doesn't work if the SIGSEGV is caused by a stack overflow, however.
Maybe I'm doing something wrong here.
I should say that I've worked with a system 5 years ago for which
userland stack expansion did work. This system ran only on
SunOS 4.1.x, however.
A similar test to the one I show below fails on Linux RH 6.0 as well.
Linux versions such as RH5.2 don't even support sigaltstack.
I tried both the case where the thread stack in question is the main
thread stack or a stack I allocated (either on the data segment or
in anonymously mmapped memory --- same result.)
I'm wondering whether this approach is really portable? For instance,
under linux-threads, you don't have the option to specify alternate stack
locations and sizes when creating a thread. POSIX 1b guarantees mprotect
to only work on mmapped() pages. Is it portable to assume that you can
mmap your own native, kernel-provided thread? I don't know.
I would really like to learn just how you do this.
You said something about the gcc implementation: do you have any pointers?
Is this part of any of the runtime libraries accompanying gcc?
- Godmar
/* stack1sparc.c
compile with gcc -o stack1sparc stack1sparc.c
Sparc/Solaris only.
run with
"./stack1sparc" for stack overflow test
"./stack1sparc -np" for sigsegv test.
*/
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/mman.h>
jmp_buf env;
jmp_buf env2;
void *guard;
void *thread_stack;
char alternate_stack[64*4096];
void handler(int sig)
{
int rc;
printf("handler stack %p\n", &rc);
mprotect(guard, 4096, PROT_READ|PROT_WRITE);
longjmp(env, 1);
}
void overflow(int i) {
int r;
if (i % 8 == 0) {
printf("%p ", &r);
}
if (i % 64 == 0) {
printf("\n");
}
overflow(i+1);
}
static int what;
void
new_thread()
{
int rc;
printf("current sp at %p\n", &rc);
if (what) {
/* demonstrate that a normal SEGFAULT works */
*(int*)0 = 42;
} else {
overflow(1);
}
}
main(int ac, char *av[])
{
stack_t ss;
int rc;
setbuf(stdout, 0);
what = ac > 1 && !strcmp(av[1], "-np");
guard = thread_stack = mmap(0, 16*4096, PROT_READ|PROT_WRITE, MAP_PRIVATE,
open("/dev/zero", O_RDWR)
, 0);
if ((int)guard == -1)
perror("mmap"), exit(0);
rc = mprotect(guard, 4096, PROT_NONE);
if (rc != 0)
perror("mprotect"), exit(0);
ss.ss_sp = &alternate_stack[(sizeof alternate_stack)/2];
ss.ss_size = (sizeof alternate_stack)/2;
ss.ss_flags = 0;
printf("alternate at %p, size is %d\n", ss.ss_sp, ss.ss_size);
rc = sigaltstack(&ss, (stack_t*)0 /* old stack_t */);
if (rc != 0)
perror("sigaltstack"), exit(0);
printf("guarding from %p-%p mystack is %p\n", guard, guard+4096, &rc);
signal(SIGSEGV, (void(*)(int))handler);
if (setjmp(env)) {
printf("okay, caught stackoverflow\n");
} else {
if (setjmp(env2)) {
new_thread();
} else {
/* fix up stack pointer */
((void**)&env2)[1] = thread_stack + 8*4096;
longjmp(env2, 1);
}
}
}