[Mono-list] catching stack overflow signals

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

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

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


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




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>

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" );

	stack_overflow( count + 1);

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

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 );
	gdstart =3D staddr - gdsize;
	gdend =3D staddr;
	ovf =3D /* FIXME */;
	ovf =3D /* FIXME */;
	if ( gdstart <=3D info->si_addr && info->si_addr < gdend )
		printf( "stack overflow, indeed\n" );
		printf( "ordinary gpf\n" );

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


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;

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;