[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--