[Mono-list] catching stack overflow signals
Dietmar Maurer
dietmar@ximian.com
19 Jun 2002 17:42:42 +0200
--=-Y5aylY+PVe/IKCnvIfnW
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
Hi all,
today I tried to find a solution to catch stack overflow signals
(segmentation fault) in order to throw a StackOverflow exception, but
unfortunately its not so easy.
On stack overflow the system raises a SIGSEGV signal and transfers
control to the handler. But that action needs the stack, so it raises
another SIGSEGV which then terminates the process immediately.
On solution is to use a separate stack for signal handler. We can use
sigaltstack () to setup such extra stack. I have attached a small test
program I found on the net to show how this works - simply compile the
program with:
gcc sigtest.c -o sigtest
The problem with that solution is that i does not work with pthread. you
can test that if you compile the program with:
gcc sigtest.c -o sigtest -lpthread
Pthread tries to determine the current thread using the stack pointer,
so this fails if we change the stack using sigaltstack.
On workaround is to use a stack allocated memory for sigaltstack, for
example we can define a local variable:
char alttack [8192] __attribute__ (( aligned (32) ));
That way we solve the above problem, but i am quite sure that this will
confuse pthread somehow, because its thread detection always points to
the same thread in signal handler.
So maybe someone knows a better solution?
- Dietmar
--=-Y5aylY+PVe/IKCnvIfnW
Content-Disposition: attachment; filename=sigtest.c
Content-Transfer-Encoding: quoted-printable
Content-Type: text/x-c; name=sigtest.c; charset=ISO-8859-1
/*
* Test program to test sigaltstack() system call.
* Does a stack overflow, which normally linux/i386 will not be able=20
* to deliver. There are other ways of demonstrating but this is
* the easiest. Of course apply the sigaltstack() patch first or
* you wont see diddly.
*/
#include <sys/signal.h>
#include <asm/unistd.h>
#include <stdio.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <sys/syscall.h>
struct sigaction act;
#define GET_STACK( x ) \
__asm__ __volatile("movl %%esp, %0\n\t" : "=3Dq" (x) : :"%0" )
void handler()
{
unsigned long ss_sp;
printf( "Caught SIGSEGV and handled stack overflow correctly.\n" );
GET_STACK( ss_sp );
printf( "signal handler stack pointer =3D %p\n", ss_sp );
exit(0);
}
void handler1()
{
printf("handler1\n");
exit(0);
}
void recurse()
{
char buf[ 4096 ];
recurse();
}
int main()
{
long ret;
struct sigaltstack sa, sa_old;
unsigned long ss_sp;
/* Step 1 - setup your alternate sig-stack */
sa.ss_sp =3D malloc( MINSIGSTKSZ );
if( !sa.ss_sp )
printf( "malloc failed\n" );
sa.ss_size =3D MINSIGSTKSZ;
sa.ss_flags =3D SS_ONSTACK;
if( sigaltstack( &sa, &sa_old ) < 0 ) {
printf( "failed to install alt-stack!\n" );
exit(0);
}
/* Step 2 - setup a sighandler and specify we want it delivered
* on the alternate stack */
act.sa_handler =3D handler;
act.sa_flags =3D SA_STACK;
#if 0
syscall (SYS_sigaction, SIGSEGV, &act, NULL);
#else
sigaction( SIGSEGV, &act, 0);
#endif=09
/* Step 3 - Generate a stack-overflow with recursion.
* Without the sigaltstack you will not handle the SIGSEGV
* because there will be no more space left on the processes
* main stack for the call.
* With the patch, you will catch it correctly! Wheee!!=20
*/
GET_STACK( ss_sp );
printf( "main stack pointer =3D %p\n", ss_sp );
recurse();
}
--=-Y5aylY+PVe/IKCnvIfnW--