-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 According to Eric Blake on 9/16/2008 4:50 PM: > I've finally figured out why c-stack is being finicky on Irix 5.3 [1]. POSIX > requires that sigaltstack be given ss_sp pointing to the smallest address in > the alternate stack. But Irix is non-compliant, and treats ss_sp as the > starting address of the stack (which, since it grows down, makes it the > largest > address in the stack).
Here's the minimal patch needed to CVS libsigsegv to expose the bug, as well as work around it for Irix 5.3. I still need to port something like this for c-stack in the non-libsigsegv case. 2008-09-20 Eric Blake <[EMAIL PROTECTED]> Detect and work around bug in Irix 5.3 sigaltstack. * m4/sigaltstack.m4 (SV_SIGALTSTACK): Test for broken stack direction in sigaltstack. * src/handler-unix.c (stackoverflow_install_handler): Adjust stack accordingly. * tests/stackoverflow1.c (stack_base): New variable. (check_stack_location): Additional check. (stackoverflow_handler, main): Use them to expose Irix bug. - -- Don't work too hard, make some time for fun as well! Eric Blake [EMAIL PROTECTED] -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (Cygwin) Comment: Public key at home.comcast.net/~ericblake/eblake.gpg Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkjVyHUACgkQ84KuGfSFAYCqfACffIR5b0vf+h21B7BAPtOxPPHW /BgAniTKRbidmw4ocOIrS5qJnwik1Nj5 =EbMO -----END PGP SIGNATURE-----
Index: src/handler-unix.c =================================================================== RCS file: /sources/libsigsegv/libsigsegv/src/handler-unix.c,v retrieving revision 1.8 diff -u -p -r1.8 handler-unix.c --- src/handler-unix.c 24 Aug 2008 13:54:16 -0000 1.8 +++ src/handler-unix.c 21 Sep 2008 04:06:19 -0000 @@ -487,6 +487,11 @@ stackoverflow_install_handler (stackover { stack_t ss; ss.ss_sp = extra_stack; +# if !SIGALTSTACK_LOW_BASE + /* Some platforms, such as Irix 5.3, mistakenly treat ss_sp as the + upper bound of the alternate stack. */ + ss.ss_sp += SIGSTKSZ - 1; +# endif ss.ss_size = extra_stack_size; ss.ss_flags = 0; /* no SS_DISABLE */ if (sigaltstack (&ss, (stack_t*)0) < 0) Index: tests/stackoverflow1.c =================================================================== RCS file: /sources/libsigsegv/libsigsegv/tests/stackoverflow1.c,v retrieving revision 1.10 diff -u -p -r1.10 stackoverflow1.c --- tests/stackoverflow1.c 24 Aug 2008 20:55:17 -0000 1.10 +++ tests/stackoverflow1.c 21 Sep 2008 04:06:19 -0000 @@ -49,6 +49,14 @@ jmp_buf mainloop; sigset_t mainsigset; volatile int pass = 0; +volatile char *stack_base; + +static void +check_stack_location (volatile char *addr) +{ + if (addr < stack_base || addr >= stack_base + SIGSTKSZ) + abort (); +} static void stackoverflow_handler_continuation (void *arg1, void *arg2, void *arg3) @@ -60,6 +68,11 @@ stackoverflow_handler_continuation (void void stackoverflow_handler (int emergency, stackoverflow_context_t scp) { + if (pass == 0) + { + char dummy; + check_stack_location (&dummy); + } pass++; printf ("Stack overflow %d caught.\n", pass); sigprocmask (SIG_SETMASK, &mainsigset, NULL); @@ -99,6 +112,7 @@ main () #endif /* Install the stack overflow handler. */ + stack_base = mystack; if (stackoverflow_install_handler (&stackoverflow_handler, mystack, sizeof (mystack)) < 0) Index: m4/sigaltstack.m4 =================================================================== RCS file: /sources/libsigsegv/libsigsegv/m4/sigaltstack.m4,v retrieving revision 1.11 diff -u -p -r1.11 sigaltstack.m4 --- m4/sigaltstack.m4 24 Aug 2008 20:55:08 -0000 1.11 +++ m4/sigaltstack.m4 21 Sep 2008 04:06:19 -0000 @@ -1,4 +1,4 @@ -# sigaltstack.m4 serial 8 (libsigsegv-2.6) +# sigaltstack.m4 serial 9 (libsigsegv-2.7) dnl Copyright (C) 2002-2006, 2008 Bruno Haible <[EMAIL PROTECTED]> dnl This file is free software, distributed under the terms of the GNU dnl General Public License. As a special exception to the GNU General @@ -123,5 +123,64 @@ int main () if test "$sv_cv_sigaltstack" != no; then AC_DEFINE(HAVE_WORKING_SIGALTSTACK, 1, [Define if you have the sigaltstack() function and it works.]) + AC_CACHE_CHECK([for correct sigaltstack boundary], + [sv_cv_sigaltstack_low_base], [ + AC_RUN_IFELSE([ + AC_LANG_SOURCE([[ +#include <stdlib.h> +#include <signal.h> +#if HAVE_SYS_SIGNAL_H +# include <sys/signal.h> +#endif +#ifndef SIGSTKSZ +# define SIGSTKSZ 16384 +#endif +volatile char *stack_base; +static void check_stack_location (volatile char *addr) +{ + if (addr >= stack_base && addr < stack_base + SIGSTKSZ) + exit (0); +} +void stackoverflow_handler (int sig) +{ + char dummy; + check_stack_location (&dummy); + exit (1); +} +int main () +{ + char mystack[SIGSTKSZ]; + stack_t altstack; + struct sigaction action; + /* Install the alternate stack. */ + stack_base = altstack.ss_sp = mystack; + altstack.ss_size = sizeof (mystack); + altstack.ss_flags = 0; /* no SS_DISABLE */ + if (sigaltstack (&altstack, NULL) < 0) + exit (1); + /* Install the SIGSEGV handler. */ + sigemptyset (&action.sa_mask); + action.sa_handler = &stackoverflow_handler; + action.sa_flags = SA_ONSTACK; + sigaction (SIGSEGV, &action, (struct sigaction *) NULL); + /* Provoke a SIGSEGV. */ + raise (SIGSEGV); + exit (2); +}]])], + [sv_cv_sigaltstack_low_base=yes], + [sv_cv_sigaltstack_low_base=no], + [ + dnl FIXME: Put in some more known values here. + case "$host_os" in + irix5*) sv_cv_sigaltstack_low_base="no" ;; + *) sv_cv_sigaltstack_low_base="guessing yes" ;; + esac + ]) + ]) + if test "$sv_cv_sigaltstack_low_base" != no; then + AC_DEFINE([SIGALTSTACK_LOW_BASE], [1], + [Define if sigaltstack() obeys POSIX by interpreting the stack + base as the low address of a range, even if the stack grows down.]) + fi fi ])