# HG changeset patch # User Eric Blake # Date 1222181246 21600 # Node ID 9867f4fee01909b8e520d5fd8f363d61e9422042 # Parent cc79b4b4da2cfc891db677f400f461a99e9634f6 c-stack: work around Irix sigaltstack bug * m4/c-stack.m4 (AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC): Check whether sigaltstack uses wrong end of stack_t (copied in part from libsigsegv). * lib/c-stack.c (c_stack_action) [!HAVE_LIBSIGSEGV]: Work around Irix bug, without requiring an over-allocation. * doc/posix-functions/sigaltstack.texi (sigaltstack): Document the bug. Signed-off-by: Eric Blake diff --git a/ChangeLog b/ChangeLog --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,14 @@ 2008-09-23 Eric Blake + c-stack: work around Irix sigaltstack bug + * m4/c-stack.m4 (AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC): Check + whether sigaltstack uses wrong end of stack_t (copied in part from + libsigsegv). + * lib/c-stack.c (c_stack_action) [!HAVE_LIBSIGSEGV]: Work around + Irix bug, without requiring an over-allocation. + * doc/posix-functions/sigaltstack.texi (sigaltstack): Document the + bug. + fopen: document mingw bug on directories * doc/posix-functions/fopen.texi (fopen): Mention mingw bug for not allowing a stream visiting a directory, even though reading @@ -38,7 +47,7 @@ success. 2008-09-22 Eric Blake - Bruno Haible + Bruno Haible vasnprintf: fix x86/glibc regression on printf("%La", 0.0L) * lib/vasnprintf.c (VASNPRINTF): Support 0.0 on platforms that @@ -138,7 +147,7 @@ digits for the exponent. 2008-09-18 Jim Meyering - Bruno Haible + Bruno Haible * lib/vasnprintf.c (decimal_point_char): Define also if NEED_PRINTF_INFINITE_LONG_DOUBLE. diff --git a/doc/posix-functions/sigaltstack.texi b/doc/posix-functions/sigaltstack.texi --- a/doc/posix-functions/sigaltstack.texi +++ b/doc/posix-functions/sigaltstack.texi @@ -16,5 +16,11 @@ This function is missing on some platforms: Cygwin, mingw, Interix 3.5, BeOS. @item -@code{sigaltstack} doesn't work on HP-UX 11/IA-64 and OpenBSD 3.6/Sparc64. +@code{sigaltstack} doesn't work on HP-UX 11/IA-64 and OpenBSD +3.6/Sparc64. +@item +This function interprets the @code{ss_sp} member of @code{stack_t} as +the upper bound instead of the lower bound of the alternate stack on +some platforms: +Irix 6.5 @end itemize diff --git a/lib/c-stack.c b/lib/c-stack.c --- a/lib/c-stack.c +++ b/lib/c-stack.c @@ -291,8 +291,15 @@ stack_t st; struct sigaction act; st.ss_flags = 0; +# if SIGALTSTACK_SS_REVERSED + /* Irix mistakenly treats ss_sp as the upper bound, rather than + lower bound, of the alternate stack. */ + st.ss_sp = alternate_signal_stack.buffer + SIGSTKSZ - sizeof (void *); + st.ss_size = sizeof alternate_signal_stack.buffer - sizeof (void *); +# else st.ss_sp = alternate_signal_stack.buffer; st.ss_size = sizeof alternate_signal_stack.buffer; +# endif r = sigaltstack (&st, NULL); if (r != 0) return r; diff --git a/m4/c-stack.m4 b/m4/c-stack.m4 --- a/m4/c-stack.m4 +++ b/m4/c-stack.m4 @@ -7,7 +7,7 @@ # Written by Paul Eggert. -# serial 6 +# serial 7 AC_DEFUN([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC], [# for STACK_DIRECTION @@ -26,13 +26,13 @@ # include # include #endif - #ifndef SIGSTKSZ - # define SIGSTKSZ 16384 - #endif + #ifndef SIGSTKSZ + # define SIGSTKSZ 16384 + #endif static union { - char buffer[SIGSTKSZ]; + char buffer[2 * SIGSTKSZ]; long double ld; long u; void *p; @@ -52,8 +52,9 @@ int r; st.ss_flags = 0; - st.ss_sp = alternate_signal_stack.buffer; - st.ss_size = sizeof alternate_signal_stack.buffer; + /* Use the midpoint to avoid Irix sigaltstack bug. */ + st.ss_sp = alternate_signal_stack.buffer + SIGSTKSZ; + st.ss_size = SIGSTKSZ; r = sigaltstack (&st, 0); if (r != 0) return r; @@ -98,6 +99,68 @@ a SIGSEGV which can be handled on an alternate stack established with sigaltstack.]) + 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], + [gl_cv_sigaltstack_low_base], [ + AC_RUN_IFELSE([ + AC_LANG_SOURCE([[ +#include +#include +#if HAVE_SYS_SIGNAL_H +# include +#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); +}]])], + [gl_cv_sigaltstack_low_base=yes], + [gl_cv_sigaltstack_low_base=no], + [gl_cv_sigaltstack_low_base=cross-compiling])]) + if test "$gl_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 + AC_CACHE_CHECK([for precise C stack overflow detection], ac_cv_sys_xsi_stack_overflow_heuristic, [AC_TRY_RUN( @@ -112,13 +175,13 @@ # include # include #endif - #ifndef SIGSTKSZ - # define SIGSTKSZ 16384 - #endif + #ifndef SIGSTKSZ + # define SIGSTKSZ 16384 + #endif static union { - char buffer[SIGSTKSZ]; + char buffer[2 * SIGSTKSZ]; long double ld; long u; void *p; @@ -141,8 +204,8 @@ { if (0 < info->si_code) { - /* For XSI heuristics to work, we need uc_stack to describe - the interrupted stack (as on Solaris), and not the + /* For XSI heuristics to work, we need uc_stack to describe + the interrupted stack (as on Solaris), and not the currently executing stack (as on Linux). */ ucontext_t const *user_context = context; char const *stack_min = user_context->uc_stack.ss_sp; @@ -167,8 +230,9 @@ int r; st.ss_flags = 0; - st.ss_sp = alternate_signal_stack.buffer; - st.ss_size = sizeof alternate_signal_stack.buffer; + /* Use the midpoint to avoid Irix sigaltstack bug. */ + st.ss_sp = alternate_signal_stack.buffer + SIGSTKSZ; + st.ss_size = SIGSTKSZ; r = sigaltstack (&st, 0); if (r != 0) return r;