changeset 10470:9867f4fee019

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 <ebb9@byu.net>
author Eric Blake <ebb9@byu.net>
date Tue, 23 Sep 2008 08:47:26 -0600
parents cc79b4b4da2c
children f318366f3bc7
files ChangeLog doc/posix-functions/sigaltstack.texi lib/c-stack.c m4/c-stack.m4
diffstat 4 files changed, 104 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- 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
@@ -138,7 +147,7 @@
 	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.
--- 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
--- 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;
--- 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 <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 @@
 	   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 <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 @@
 	 # 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 @@
 	 {
 	   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;