install-reloc: Support multi-binary installation.
[gnulib.git] / m4 / c-stack.m4
index 8049d96..5760dbe 100644 (file)
 # Check prerequisites for compiling lib/c-stack.c.
 
-# Copyright (C) 2002, 2003 Free Software Foundation, Inc.
-
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, or (at your option)
-# any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-# 02111-1307, USA.
+# Copyright (C) 2002-2004, 2008-2013 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
 
 # Written by Paul Eggert.
 
+# serial 15
+
 AC_DEFUN([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC],
-  [# for STACK_DIRECTION
-   AC_REQUIRE([AC_FUNC_ALLOCA])
-   AC_CHECK_FUNCS(setrlimit)
+  [
+   AC_REQUIRE([AC_CANONICAL_HOST])
+   AC_CHECK_FUNCS_ONCE([setrlimit])
+   AC_CHECK_HEADERS_ONCE([ucontext.h])
+
+   dnl List of signals that are sent when an invalid virtual memory address
+   dnl is accessed, or when the stack overflows.
+   dnl Either { SIGSEGV } or { SIGSEGV, SIGBUS }.
+   case "$host_os" in
+     sunos4* | freebsd* | dragonfly* | openbsd* | mirbsd* | netbsd* | kfreebsd* | knetbsd*) # BSD systems
+       FAULT_YIELDS_SIGBUS=1 ;;
+     hpux*) # HP-UX
+       FAULT_YIELDS_SIGBUS=1 ;;
+     macos* | darwin*) # Mac OS X
+       FAULT_YIELDS_SIGBUS=1 ;;
+     gnu*) # Hurd
+       FAULT_YIELDS_SIGBUS=1 ;;
+     *)
+       FAULT_YIELDS_SIGBUS=0 ;;
+   esac
+   AC_DEFINE_UNQUOTED([FAULT_YIELDS_SIGBUS], [$FAULT_YIELDS_SIGBUS],
+     [Define to 1 if an invalid memory address access may yield a SIGBUS.])
 
    AC_CACHE_CHECK([for working C stack overflow detection],
+     [ac_cv_sys_stack_overflow_works],
+     [AC_RUN_IFELSE([AC_LANG_SOURCE(
+           [[
+            #include <unistd.h>
+            #include <signal.h>
+            #if HAVE_SETRLIMIT
+            # include <sys/types.h>
+            # include <sys/time.h>
+            # include <sys/resource.h>
+            #endif
+            #ifndef SIGSTKSZ
+            # define SIGSTKSZ 16384
+            #endif
+
+            static union
+            {
+              char buffer[2 * SIGSTKSZ];
+              long double ld;
+              long u;
+              void *p;
+            } alternate_signal_stack;
+
+            static void
+            segv_handler (int signo)
+            {
+              _exit (0);
+            }
+
+            static int
+            c_stack_action ()
+            {
+              stack_t st;
+              struct sigaction act;
+              int r;
+
+              st.ss_flags = 0;
+              /* 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 1;
+
+              sigemptyset (&act.sa_mask);
+              act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
+              act.sa_handler = segv_handler;
+              #if FAULT_YIELDS_SIGBUS
+              if (sigaction (SIGBUS, &act, 0) < 0)
+                return 2;
+              #endif
+              if (sigaction (SIGSEGV, &act, 0) < 0)
+                return 3;
+              return 0;
+            }
+            static volatile int *
+            recurse_1 (volatile int n, volatile int *p)
+            {
+              if (n >= 0)
+                *recurse_1 (n + 1, p) += n;
+              return p;
+            }
+            static int
+            recurse (volatile int n)
+            {
+              int sum = 0;
+              return *recurse_1 (n, &sum);
+            }
+            int
+            main ()
+            {
+              int result;
+              #if HAVE_SETRLIMIT && defined RLIMIT_STACK
+              /* Before starting the endless recursion, try to be friendly
+                 to the user's machine.  On some Linux 2.2.x systems, there
+                 is no stack limit for user processes at all.  We don't want
+                 to kill such systems.  */
+              struct rlimit rl;
+              rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
+              setrlimit (RLIMIT_STACK, &rl);
+              #endif
+
+              result = c_stack_action ();
+              if (result != 0)
+                return result;
+              return recurse (0);
+            }
+           ]])],
+        [ac_cv_sys_stack_overflow_works=yes],
+        [ac_cv_sys_stack_overflow_works=no],
+        [ac_cv_sys_stack_overflow_works=cross-compiling])])
+
+  if test $ac_cv_sys_stack_overflow_works = yes; then
+   AC_DEFINE([HAVE_STACK_OVERFLOW_HANDLING], [1],
+     [Define to 1 if extending the stack slightly past the limit causes
+      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 (4);
+}]])],
+      [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(
-       [
-        #include <unistd.h>
-        #include <signal.h>
-        #include <ucontext.h>
-        #if HAVE_SETRLIMIT
-        # include <sys/types.h>
-        # include <sys/time.h>
-        # include <sys/resource.h>
-        #endif
-
-        static union
-        {
-          char buffer[SIGSTKSZ];
-          long double ld;
-          long u;
-          void *p;
-        } alternate_signal_stack;
-
-        #if STACK_DIRECTION
-        # define find_stack_direction(ptr) STACK_DIRECTION
-        #else
-        static int
-        find_stack_direction (char const *addr)
-        {
-          char dummy;
-          return (! addr ? find_stack_direction (&dummy)
-                  : addr < &dummy ? 1 : -1);
-        }
-        #endif
-
-        static void
-        segv_handler (int signo, siginfo_t *info, void *context)
-        {
-          if (0 < info->si_code)
-            {
-              ucontext_t const *user_context = context;
-              char const *stack_min = user_context->uc_stack.ss_sp;
-              size_t stack_size = user_context->uc_stack.ss_size;
-              char const *faulting_address = info->si_addr;
-              size_t s = faulting_address - stack_min;
-              size_t page_size = sysconf (_SC_PAGESIZE);
-              if (find_stack_direction (0) < 0)
-                s += page_size;
-              if (s < stack_size + page_size)
-                _exit (0);
-            }
-
-          _exit (1);
-        }
-
-        static int
-        c_stack_action (void)
-        {
-          stack_t st;
-          struct sigaction act;
-          int r;
-
-          st.ss_flags = 0;
-          st.ss_sp = alternate_signal_stack.buffer;
-          st.ss_size = sizeof alternate_signal_stack.buffer;
-          r = sigaltstack (&st, 0);
-          if (r != 0)
-            return r;
-
-          sigemptyset (&act.sa_mask);
-          act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
-          act.sa_sigaction = segv_handler;
-          return sigaction (SIGSEGV, &act, 0);
-        }
-
-        static int
-        recurse (char *p)
-        {
-          char array[500];
-          array[0] = 1;
-          return *p + recurse (array);
-        }
-
-        int
-        main (void)
-        {
-          #if HAVE_SETRLIMIT && defined RLIMIT_STACK
-          /* Before starting the endless recursion, try to be friendly
-             to the user's machine.  On some Linux 2.2.x systems, there
-             is no stack limit for user processes at all.  We don't want
-             to kill such systems.  */
-          struct rlimit rl;
-          rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
-          setrlimit (RLIMIT_STACK, &rl);
-          #endif
-
-          c_stack_action ();
-          return recurse ("\1");
-        }
-       ],
-       [ac_cv_sys_xsi_stack_overflow_heuristic=yes],
-       [ac_cv_sys_xsi_stack_overflow_heuristic=no],
-       [ac_cv_sys_xsi_stack_overflow_heuristic=cross-compiling])])
+     [AC_RUN_IFELSE([AC_LANG_SOURCE(
+           [[
+            #include <unistd.h>
+            #include <signal.h>
+            #if HAVE_UCONTEXT_H
+            # include <ucontext.h>
+            #endif
+            #if HAVE_SETRLIMIT
+            # include <sys/types.h>
+            # include <sys/time.h>
+            # include <sys/resource.h>
+            #endif
+            #ifndef SIGSTKSZ
+            # define SIGSTKSZ 16384
+            #endif
+
+            static union
+            {
+              char buffer[2 * SIGSTKSZ];
+              long double ld;
+              long u;
+              void *p;
+            } alternate_signal_stack;
+
+            #if STACK_DIRECTION
+            # define find_stack_direction(ptr) STACK_DIRECTION
+            #else
+            static int
+            find_stack_direction (char const *addr)
+            {
+              char dummy;
+              return (! addr ? find_stack_direction (&dummy)
+                      : addr < &dummy ? 1 : -1);
+            }
+            #endif
+
+            static void
+            segv_handler (int signo, siginfo_t *info, void *context)
+            {
+              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
+                     currently executing stack (as on Linux).  */
+                  ucontext_t const *user_context = context;
+                  char const *stack_min = user_context->uc_stack.ss_sp;
+                  size_t stack_size = user_context->uc_stack.ss_size;
+                  char const *faulting_address = info->si_addr;
+                  size_t s = faulting_address - stack_min;
+                  size_t page_size = sysconf (_SC_PAGESIZE);
+                  if (find_stack_direction (0) < 0)
+                    s += page_size;
+                  if (s < stack_size + page_size)
+                    _exit (0);
+                  _exit (4);
+                }
+              _exit (5);
+            }
+
+            static int
+            c_stack_action ()
+            {
+              stack_t st;
+              struct sigaction act;
+              int r;
+
+              st.ss_flags = 0;
+              /* 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 1;
+
+              sigemptyset (&act.sa_mask);
+              act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
+              act.sa_sigaction = segv_handler;
+              #if FAULT_YIELDS_SIGBUS
+              if (sigaction (SIGBUS, &act, 0) < 0)
+                return 2;
+              #endif
+              if (sigaction (SIGSEGV, &act, 0) < 0)
+                return 3;
+              return 0;
+            }
+            static volatile int *
+            recurse_1 (volatile int n, volatile int *p)
+            {
+              if (n >= 0)
+                *recurse_1 (n + 1, p) += n;
+              return p;
+            }
+            static int
+            recurse (volatile int n)
+            {
+              int sum = 0;
+              return *recurse_1 (n, &sum);
+            }
+            int
+            main ()
+            {
+              int result;
+              #if HAVE_SETRLIMIT && defined RLIMIT_STACK
+              /* Before starting the endless recursion, try to be friendly
+                 to the user's machine.  On some Linux 2.2.x systems, there
+                 is no stack limit for user processes at all.  We don't want
+                 to kill such systems.  */
+              struct rlimit rl;
+              rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
+              setrlimit (RLIMIT_STACK, &rl);
+              #endif
+
+              result = c_stack_action ();
+              if (result != 0)
+                return result;
+              return recurse (0);
+            }
+           ]])],
+        [ac_cv_sys_xsi_stack_overflow_heuristic=yes],
+        [ac_cv_sys_xsi_stack_overflow_heuristic=no],
+        [ac_cv_sys_xsi_stack_overflow_heuristic=cross-compiling])])
 
    if test $ac_cv_sys_xsi_stack_overflow_heuristic = yes; then
-     AC_DEFINE(HAVE_XSI_STACK_OVERFLOW_HEURISTIC, 1,
+     AC_DEFINE([HAVE_XSI_STACK_OVERFLOW_HEURISTIC], [1],
        [Define to 1 if extending the stack slightly past the limit causes
-       a SIGSEGV, and an alternate stack can be established with sigaltstack,
-       and the signal handler is passed a context that specifies the
-       run time stack.  This behavior is defined by POSIX 1003.1-2001
+        a SIGSEGV, and an alternate stack can be established with sigaltstack,
+        and the signal handler is passed a context that specifies the
+        run time stack.  This behavior is defined by POSIX 1003.1-2001
         with the X/Open System Interface (XSI) option
-       and is a standardized way to implement a SEGV-based stack
+        and is a standardized way to implement a SEGV-based stack
         overflow detection heuristic.])
-   fi])
+   fi
+  fi])
 
 
-AC_DEFUN([jm_PREREQ_C_STACK],
+AC_DEFUN([gl_PREREQ_C_STACK],
   [AC_REQUIRE([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC])
+   AC_REQUIRE([gl_LIBSIGSEGV])
 
    # for STACK_DIRECTION
    AC_REQUIRE([AC_FUNC_ALLOCA])
 
-   AC_CHECK_FUNCS(getcontext sigaltstack)
-   AC_CHECK_DECLS([getcontext], , , [#include <ucontext.h>])
-   AC_CHECK_DECLS([sigaltstack], , , [#include <signal.h>])
+   AC_CHECK_FUNCS_ONCE([sigaltstack])
+   AC_CHECK_DECLS([sigaltstack], , , [[#include <signal.h>]])
+
+   AC_CHECK_HEADERS_ONCE([unistd.h ucontext.h])
 
-   AC_CHECK_HEADERS_ONCE(sys/time.h unistd.h)
-   AC_CHECK_HEADERS(sys/resource.h ucontext.h)
+   AC_CHECK_TYPES([stack_t], , , [#include <signal.h>])
 
-   AC_CHECK_TYPES([stack_t], , , [#include <signal.h>])])
+   dnl c-stack does not need -lsigsegv if the system has XSI heuristics.
+   if test "$gl_cv_lib_sigsegv" = yes \
+       && test $"ac_cv_sys_xsi_stack_overflow_heuristic" != yes ; then
+     AC_SUBST([LIBCSTACK], [$LIBSIGSEGV])
+     AC_SUBST([LTLIBCSTACK], [$LTLIBSIGSEGV])
+   fi
+])
 
 AC_DEFUN([gl_C_STACK],
 [
   dnl Prerequisites of lib/c-stack.c.
-  jm_PREREQ_C_STACK
+  gl_PREREQ_C_STACK
 ])