[Mono-list] catching stack overflow signals

Daniel Stodden stodden@in.tum.de
21 Jun 2002 04:04:41 +0200


--=-xUP2407B3E4x0NcwP0wM
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

On Wed, 2002-06-19 at 17:42, Dietmar Maurer wrote:
> Hi all,

hi.

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

indeed it would.

> So maybe someone knows a better solution?

i don't see any alternative to altstack.

win32 seems to handle the overflow problem more elegantly by releasing
the page protection bit on the guard. exception handlers can then try to
recover from within the guard region. [1]

sigaltstack however seems at least to be smart enough _not_ to share
alternates between threads. 
i haven't looked this up in the kernel yet, though.
seems installing an altstack on on a per thread start basis fixes the
problem. see the attached update.

regards,
dns

[1]http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaskdr/html/drgui49.asp

-- 
___________________________________________________________________________
 mailto:stodden@in.tum.de

--=-xUP2407B3E4x0NcwP0wM
Content-Disposition: attachment; filename=sigtest2.c
Content-Transfer-Encoding: quoted-printable
Content-Type: text/x-c; name=sigtest2.c; charset=ISO-8859-1

#include <stdlib.h>
#include <sys/signal.h>
#define __USE_GNU
#include <pthread.h>
#include <setjmp.h>

void
stack_overflow( int count )
{
	char buf[2 * pthread_self()];

	printf( "thread=3D%d count=3D%d, stack=3D%p\n",=20
		pthread_self(), count, buf );

	if ( count % 10 =3D=3D 0 ) {
		printf( "-- yield --\n" );
		pthread_yield();
	}

	stack_overflow( count + 1);
}

#ifdef __i386__
#define _STACK_GROWS_DOWN       1
#else
#error "intel outside, huh?"
#endif

void sa_segv_action( int sig, siginfo_t *info, void *arg )
{
	int ss_sp;
	pthread_t self =3D pthread_self();
	pthread_attr_t attr;
	void *staddr;
	size_t stsize;
	void *gdstart, *gdend;
	size_t gdsize;
	int ovf =3D 0;

	printf( "caught signal: thread=3D%d, ss_sp=3D%p\n",=20
		self, &ss_sp );
	printf( "fault at:   %p\n", info->si_addr );

	// FIXME: won't work for the parent
	pthread_getattr_np( self, &attr );
	pthread_attr_getstack( &attr, &staddr, &stsize );
	pthread_attr_getguardsize( &attr, &gdsize );
	printf( "stack addr: %p\n", staddr );
	printf( "guard size: %p\n", gdsize );
=09
#if _STACK_GROWS_DOWN
	gdstart =3D staddr - gdsize;
	gdend =3D staddr;
#elif _STACK_GROWS_UP
	ovf =3D /* FIXME */;
#elif NEED_SEPARATE_REGISTER_STACK
	ovf =3D /* FIXME */;
#endif
	if ( gdstart <=3D info->si_addr && info->si_addr < gdend )
		printf( "stack overflow, indeed\n" );
	else
		printf( "ordinary gpf\n" );

	printf( "-- die --\n" );
	pthread_exit( NULL );
}

#define STACKSIZE SIGSTKSZ

void *
thread_start( void *arg )
{
	struct sigaltstack sa;
	char altstack[SIGSTKSZ];

	sa.ss_sp =3D altstack;
	sa.ss_size =3D STACKSIZE;
	sa.ss_flags =3D SS_ONSTACK;
	sigaltstack( &sa, NULL );

	printf( "thread starts: self=3D%d, stack=3D%p\n", pthread_self(), altstack=
 );

	stack_overflow( 0 );

	return NULL;
}

int
main( int argc, char **argv )
{
	pthread_attr_t attr;
	size_t guardsize;
	pthread_t thread1, thread2;
	struct sigaction act;

	act.sa_sigaction =3D sa_segv_action;
	act.sa_flags =3D SA_SIGINFO | SA_ONSTACK;
	sigaction( SIGSEGV, &act, 0);

	pthread_attr_getguardsize( &attr, &guardsize );
	printf( "guardsize=3D%d\n", guardsize );

	if ( pthread_create( &thread1, NULL, thread_start, NULL ) ) {
		printf( "could not create first thread\n" );
		exit( 1 );
	}

	if ( pthread_create( &thread2, NULL, thread_start, NULL ) ) {
		printf( "could not create second thread\n" );
		exit( 1 );
	}

	pthread_join( thread1, NULL );
	pthread_join( thread2, NULL );

	return 0;
}

--=-xUP2407B3E4x0NcwP0wM--