Hi Eric, > Here's the minimal patch needed to CVS libsigsegv to expose the bug, as > well as work around it for Irix 5.3.
Nice work! I'm applying this only slightly modified version. - In the configuration test, keep room to both sides of the ss_sp value. On IRIX, we don't want the test to crash. We want it to exit(1) reasonably. - When setting the stack_t in a reversed way, since we don't know exactly how the fields are interpreted, don't pass an odd address and reduce the size a bit. (Hope that still works!) I've put up a new tarball at http://www.haible.de/bruno/gnu/libsigsegv-2.7-pre1.tar.gz 2008-09-21 Eric Blake <[EMAIL PROTECTED]> Bruno Haible <[EMAIL PROTECTED]> Detect and work around bug in Irix 5.3 sigaltstack. * m4/sigaltstack.m4 (SV_SIGALTSTACK): Test for broken stack_t direction in sigaltstack. * src/handler-unix.c (stackoverflow_install_handler): Adjust stack accordingly. * tests/stackoverflow1.c (stack_lower_bound, stack_upper_bound): New variables. (stackoverflow_handler): Use them to expose IRIX bug. (main): Initialize them. *** NEWS 24 Aug 2008 22:24:52 -0000 1.21 --- NEWS 21 Sep 2008 13:36:42 -0000 *************** *** 1,3 **** --- 1,7 ---- + New in 2.7: + + * Support for IRIX 5.3. Contributed by Eric Blake. + New in 2.6: * sigsegv_leave_handler is changed. Previously it was a normal function with *** README 24 Aug 2008 13:54:32 -0000 1.7 --- README 21 Sep 2008 13:36:42 -0000 *************** *** 106,111 **** --- 106,112 ---- Copyright 1998-1999, 2002-2008 Bruno Haible <[EMAIL PROTECTED]> Copyright 2002-2005 Paolo Bonzini <[EMAIL PROTECTED]> + Copyright 2008 Eric Blake <[EMAIL PROTECTED]> This is free software distributed under the GNU General Public Licence described in the file COPYING. There is ABSOLUTELY NO WARRANTY, explicit or *** m4/sigaltstack.m4 24 Aug 2008 20:55:08 -0000 1.11 --- m4/sigaltstack.m4 21 Sep 2008 13:36:42 -0000 *************** *** 1,5 **** ! # sigaltstack.m4 serial 8 (libsigsegv-2.6) 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 dnl Public License, this file may be distributed as part of a program --- 1,6 ---- ! # sigaltstack.m4 serial 9 (libsigsegv-2.7) dnl Copyright (C) 2002-2006, 2008 Bruno Haible <[EMAIL PROTECTED]> + dnl Copyright (C) 2008 Eric Blake <[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 dnl Public License, this file may be distributed as part of a program *************** *** 123,127 **** --- 124,197 ---- if test "$sv_cv_sigaltstack" != no; then AC_DEFINE(HAVE_WORKING_SIGALTSTACK, 1, [Define if you have the sigaltstack() function and it works.]) + + dnl The ss_sp field of a stack_t is, according to POSIX, the lowest address + dnl of the memory block designated as an alternate stack. But IRIX 5.3 + dnl interprets it as the highest address! + AC_CACHE_CHECK([for correct stack_t interpretation], + [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_lower_bound; + volatile char *stack_upper_bound; + static void check_stack_location (volatile char *addr) + { + if (addr >= stack_lower_bound && addr <= stack_upper_bound) + exit (0); + else + exit (1); + } + static void stackoverflow_handler (int sig) + { + char dummy; + check_stack_location (&dummy); + } + int main () + { + char mystack[2 * SIGSTKSZ]; + stack_t altstack; + struct sigaction action; + /* Install the alternate stack. */ + altstack.ss_sp = mystack + SIGSTKSZ; + altstack.ss_size = SIGSTKSZ; + stack_lower_bound = (char *) altstack.ss_sp; + stack_upper_bound = (char *) altstack.ss_sp + altstack.ss_size - 1; + altstack.ss_flags = 0; /* no SS_DISABLE */ + if (sigaltstack (&altstack, NULL) < 0) + exit (2); + /* Install the SIGSEGV handler. */ + sigemptyset (&action.sa_mask); + action.sa_handler = &stackoverflow_handler; + action.sa_flags = SA_ONSTACK; + if (sigaction (SIGSEGV, &action, (struct sigaction *) NULL) < 0) + exit(3); + /* Provoke a SIGSEGV. */ + raise (SIGSEGV); + exit (3); + }]])], + [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_SS_REVERSED], [1], + [Define if sigaltstack() interprets the stack_t.ss_sp field incorrectly, + as the highest address of the alternate stack range rather than as the + lowest address.]) + fi fi ]) *** src/handler-unix.c 24 Aug 2008 13:54:16 -0000 1.8 --- src/handler-unix.c 21 Sep 2008 13:36:42 -0000 *************** *** 486,493 **** --- 486,498 ---- #else /* HAVE_SIGALTSTACK */ { stack_t ss; + #if SIGALTSTACK_SS_REVERSED + ss.ss_sp = extra_stack + extra_stack_size - sizeof (void *); + ss.ss_size = extra_stack_size - sizeof (void *); + #else ss.ss_sp = extra_stack; ss.ss_size = extra_stack_size; + #endif ss.ss_flags = 0; /* no SS_DISABLE */ if (sigaltstack (&ss, (stack_t*)0) < 0) return -1; *** tests/stackoverflow1.c 24 Aug 2008 20:55:17 -0000 1.10 --- tests/stackoverflow1.c 21 Sep 2008 13:36:42 -0000 *************** *** 50,55 **** --- 50,58 ---- volatile int pass = 0; + volatile char *stack_lower_bound; + volatile char *stack_upper_bound; + static void stackoverflow_handler_continuation (void *arg1, void *arg2, void *arg3) { *************** *** 60,65 **** --- 63,72 ---- void stackoverflow_handler (int emergency, stackoverflow_context_t scp) { + char dummy; + volatile char *addr = &dummy; + if (!(addr >= stack_lower_bound && addr <= stack_upper_bound)) + abort (); pass++; printf ("Stack overflow %d caught.\n", pass); sigprocmask (SIG_SETMASK, &mainsigset, NULL); *************** *** 103,108 **** --- 110,117 ---- mystack, sizeof (mystack)) < 0) exit (2); + stack_lower_bound = mystack; + stack_upper_bound = mystack + sizeof (mystack) - 1; /* Save the current signal mask. */ sigemptyset (&emptyset);