c-stack: work around Irix sigaltstack bug
authorEric Blake <ebb9@byu.net>
Tue, 23 Sep 2008 14:47:26 +0000 (08:47 -0600)
committerEric Blake <ebb9@byu.net>
Tue, 23 Sep 2008 14:47:26 +0000 (08:47 -0600)
* 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 <ebb9@byu.net>
ChangeLog
doc/posix-functions/sigaltstack.texi
lib/c-stack.c
m4/c-stack.m4

index 38dd15e..1dbbb60 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2008-09-23  Eric Blake  <ebb9@byu.net>
 
+       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  <ebb9@byu.net>
-            Bruno Haible  <bruno@clisp.org>
+           Bruno Haible  <bruno@clisp.org>
 
        vasnprintf: fix x86/glibc regression on printf("%La", 0.0L)
        * lib/vasnprintf.c (VASNPRINTF): Support 0.0 on platforms that
        digits for the exponent.
 
 2008-09-18  Jim Meyering  <meyering@redhat.com>
-            Bruno Haible  <bruno@clisp.org>
+           Bruno Haible  <bruno@clisp.org>
 
        * lib/vasnprintf.c (decimal_point_char): Define also if
        NEED_PRINTF_INFINITE_LONG_DOUBLE.
index 53d91c7..e318ebe 100644 (file)
@@ -16,5 +16,11 @@ Portability problems not fixed by Gnulib:
 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
index 6802665..11cb9ef 100644 (file)
@@ -291,8 +291,15 @@ c_stack_action (void (*action) (int))
   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;
index 4f0300b..f1bda7b 100644 (file)
@@ -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 @@ AC_DEFUN([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC],
         # include <sys/time.h>
         # include <sys/resource.h>
         #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 @@ AC_DEFUN([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC],
           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 @@ AC_DEFUN([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC],
       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 <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);
+}]])],
+      [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 @@ AC_DEFUN([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC],
         # include <sys/time.h>
         # include <sys/resource.h>
         #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 @@ AC_DEFUN([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC],
         {
           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 @@ AC_DEFUN([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC],
           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;