Blame m4/c-stack.m4

Packit 33f14e
# Check prerequisites for compiling lib/c-stack.c.
Packit 33f14e
Packit 33f14e
# Copyright (C) 2002-2004, 2008-2017 Free Software Foundation, Inc.
Packit 33f14e
# This file is free software; the Free Software Foundation
Packit 33f14e
# gives unlimited permission to copy and/or distribute it,
Packit 33f14e
# with or without modifications, as long as this notice is preserved.
Packit 33f14e
Packit 33f14e
# Written by Paul Eggert.
Packit 33f14e
Packit 33f14e
# serial 15
Packit 33f14e
Packit 33f14e
AC_DEFUN([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC],
Packit 33f14e
  [
Packit 33f14e
   AC_REQUIRE([AC_CANONICAL_HOST])
Packit 33f14e
   AC_CHECK_FUNCS_ONCE([setrlimit])
Packit 33f14e
   AC_CHECK_HEADERS_ONCE([ucontext.h])
Packit 33f14e
Packit 33f14e
   dnl List of signals that are sent when an invalid virtual memory address
Packit 33f14e
   dnl is accessed, or when the stack overflows.
Packit 33f14e
   dnl Either { SIGSEGV } or { SIGSEGV, SIGBUS }.
Packit 33f14e
   case "$host_os" in
Packit 33f14e
     sunos4* | freebsd* | dragonfly* | openbsd* | mirbsd* | netbsd* | kfreebsd* | knetbsd*) # BSD systems
Packit 33f14e
       FAULT_YIELDS_SIGBUS=1 ;;
Packit 33f14e
     hpux*) # HP-UX
Packit 33f14e
       FAULT_YIELDS_SIGBUS=1 ;;
Packit 33f14e
     macos* | darwin*) # Mac OS X
Packit 33f14e
       FAULT_YIELDS_SIGBUS=1 ;;
Packit 33f14e
     gnu*) # Hurd
Packit 33f14e
       FAULT_YIELDS_SIGBUS=1 ;;
Packit 33f14e
     *)
Packit 33f14e
       FAULT_YIELDS_SIGBUS=0 ;;
Packit 33f14e
   esac
Packit 33f14e
   AC_DEFINE_UNQUOTED([FAULT_YIELDS_SIGBUS], [$FAULT_YIELDS_SIGBUS],
Packit 33f14e
     [Define to 1 if an invalid memory address access may yield a SIGBUS.])
Packit 33f14e
Packit 33f14e
   AC_CACHE_CHECK([for working C stack overflow detection],
Packit 33f14e
     [ac_cv_sys_stack_overflow_works],
Packit 33f14e
     [AC_RUN_IFELSE([AC_LANG_SOURCE(
Packit 33f14e
           [[
Packit 33f14e
            #include <unistd.h>
Packit 33f14e
            #include <signal.h>
Packit 33f14e
            #if HAVE_SETRLIMIT
Packit 33f14e
            # include <sys/types.h>
Packit 33f14e
            # include <sys/time.h>
Packit 33f14e
            # include <sys/resource.h>
Packit 33f14e
            #endif
Packit 33f14e
            #ifndef SIGSTKSZ
Packit 33f14e
            # define SIGSTKSZ 16384
Packit 33f14e
            #endif
Packit 33f14e
Packit 33f14e
            static union
Packit 33f14e
            {
Packit 33f14e
              char buffer[2 * SIGSTKSZ];
Packit 33f14e
              long double ld;
Packit 33f14e
              long u;
Packit 33f14e
              void *p;
Packit 33f14e
            } alternate_signal_stack;
Packit 33f14e
Packit 33f14e
            static void
Packit 33f14e
            segv_handler (int signo)
Packit 33f14e
            {
Packit 33f14e
              _exit (0);
Packit 33f14e
            }
Packit 33f14e
Packit 33f14e
            static int
Packit 33f14e
            c_stack_action ()
Packit 33f14e
            {
Packit 33f14e
              stack_t st;
Packit 33f14e
              struct sigaction act;
Packit 33f14e
              int r;
Packit 33f14e
Packit 33f14e
              st.ss_flags = 0;
Packit 33f14e
              /* Use the midpoint to avoid Irix sigaltstack bug.  */
Packit 33f14e
              st.ss_sp = alternate_signal_stack.buffer + SIGSTKSZ;
Packit 33f14e
              st.ss_size = SIGSTKSZ;
Packit 33f14e
              r = sigaltstack (&st, 0);
Packit 33f14e
              if (r != 0)
Packit 33f14e
                return 1;
Packit 33f14e
Packit 33f14e
              sigemptyset (&act.sa_mask);
Packit 33f14e
              act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
Packit 33f14e
              act.sa_handler = segv_handler;
Packit 33f14e
              #if FAULT_YIELDS_SIGBUS
Packit 33f14e
              if (sigaction (SIGBUS, &act, 0) < 0)
Packit 33f14e
                return 2;
Packit 33f14e
              #endif
Packit 33f14e
              if (sigaction (SIGSEGV, &act, 0) < 0)
Packit 33f14e
                return 3;
Packit 33f14e
              return 0;
Packit 33f14e
            }
Packit 33f14e
            static volatile int *
Packit 33f14e
            recurse_1 (volatile int n, volatile int *p)
Packit 33f14e
            {
Packit 33f14e
              if (n >= 0)
Packit 33f14e
                *recurse_1 (n + 1, p) += n;
Packit 33f14e
              return p;
Packit 33f14e
            }
Packit 33f14e
            static int
Packit 33f14e
            recurse (volatile int n)
Packit 33f14e
            {
Packit 33f14e
              int sum = 0;
Packit 33f14e
              return *recurse_1 (n, &sum);
Packit 33f14e
            }
Packit 33f14e
            int
Packit 33f14e
            main ()
Packit 33f14e
            {
Packit 33f14e
              int result;
Packit 33f14e
              #if HAVE_SETRLIMIT && defined RLIMIT_STACK
Packit 33f14e
              /* Before starting the endless recursion, try to be friendly
Packit 33f14e
                 to the user's machine.  On some Linux 2.2.x systems, there
Packit 33f14e
                 is no stack limit for user processes at all.  We don't want
Packit 33f14e
                 to kill such systems.  */
Packit 33f14e
              struct rlimit rl;
Packit 33f14e
              rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
Packit 33f14e
              setrlimit (RLIMIT_STACK, &rl);
Packit 33f14e
              #endif
Packit 33f14e
Packit 33f14e
              result = c_stack_action ();
Packit 33f14e
              if (result != 0)
Packit 33f14e
                return result;
Packit 33f14e
              return recurse (0);
Packit 33f14e
            }
Packit 33f14e
           ]])],
Packit 33f14e
        [ac_cv_sys_stack_overflow_works=yes],
Packit 33f14e
        [ac_cv_sys_stack_overflow_works=no],
Packit 33f14e
        [ac_cv_sys_stack_overflow_works=cross-compiling])])
Packit 33f14e
Packit 33f14e
  if test $ac_cv_sys_stack_overflow_works = yes; then
Packit 33f14e
   AC_DEFINE([HAVE_STACK_OVERFLOW_HANDLING], [1],
Packit 33f14e
     [Define to 1 if extending the stack slightly past the limit causes
Packit 33f14e
      a SIGSEGV which can be handled on an alternate stack established
Packit 33f14e
      with sigaltstack.])
Packit 33f14e
Packit 33f14e
    dnl The ss_sp field of a stack_t is, according to POSIX, the lowest address
Packit 33f14e
    dnl of the memory block designated as an alternate stack. But IRIX 5.3
Packit 33f14e
    dnl interprets it as the highest address!
Packit 33f14e
    AC_CACHE_CHECK([for correct stack_t interpretation],
Packit 33f14e
      [gl_cv_sigaltstack_low_base], [
Packit 33f14e
      AC_RUN_IFELSE([
Packit 33f14e
        AC_LANG_SOURCE([[
Packit 33f14e
#include <stdlib.h>
Packit 33f14e
#include <signal.h>
Packit 33f14e
#if HAVE_SYS_SIGNAL_H
Packit 33f14e
# include <sys/signal.h>
Packit 33f14e
#endif
Packit 33f14e
#ifndef SIGSTKSZ
Packit 33f14e
# define SIGSTKSZ 16384
Packit 33f14e
#endif
Packit 33f14e
volatile char *stack_lower_bound;
Packit 33f14e
volatile char *stack_upper_bound;
Packit 33f14e
static void check_stack_location (volatile char *addr)
Packit 33f14e
{
Packit 33f14e
  if (addr >= stack_lower_bound && addr <= stack_upper_bound)
Packit 33f14e
    exit (0);
Packit 33f14e
  else
Packit 33f14e
    exit (1);
Packit 33f14e
}
Packit 33f14e
static void stackoverflow_handler (int sig)
Packit 33f14e
{
Packit 33f14e
  char dummy;
Packit 33f14e
  check_stack_location (&dummy);
Packit 33f14e
}
Packit 33f14e
int main ()
Packit 33f14e
{
Packit 33f14e
  char mystack[2 * SIGSTKSZ];
Packit 33f14e
  stack_t altstack;
Packit 33f14e
  struct sigaction action;
Packit 33f14e
  /* Install the alternate stack.  */
Packit 33f14e
  altstack.ss_sp = mystack + SIGSTKSZ;
Packit 33f14e
  altstack.ss_size = SIGSTKSZ;
Packit 33f14e
  stack_lower_bound = (char *) altstack.ss_sp;
Packit 33f14e
  stack_upper_bound = (char *) altstack.ss_sp + altstack.ss_size - 1;
Packit 33f14e
  altstack.ss_flags = 0; /* no SS_DISABLE */
Packit 33f14e
  if (sigaltstack (&altstack, NULL) < 0)
Packit 33f14e
    exit (2);
Packit 33f14e
  /* Install the SIGSEGV handler.  */
Packit 33f14e
  sigemptyset (&action.sa_mask);
Packit 33f14e
  action.sa_handler = &stackoverflow_handler;
Packit 33f14e
  action.sa_flags = SA_ONSTACK;
Packit 33f14e
  if (sigaction (SIGSEGV, &action, (struct sigaction *) NULL) < 0)
Packit 33f14e
    exit(3);
Packit 33f14e
  /* Provoke a SIGSEGV.  */
Packit 33f14e
  raise (SIGSEGV);
Packit 33f14e
  exit (4);
Packit 33f14e
}]])],
Packit 33f14e
      [gl_cv_sigaltstack_low_base=yes],
Packit 33f14e
      [gl_cv_sigaltstack_low_base=no],
Packit 33f14e
      [gl_cv_sigaltstack_low_base=cross-compiling])])
Packit 33f14e
   if test "$gl_cv_sigaltstack_low_base" = no; then
Packit 33f14e
      AC_DEFINE([SIGALTSTACK_SS_REVERSED], [1],
Packit 33f14e
        [Define if sigaltstack() interprets the stack_t.ss_sp field
Packit 33f14e
         incorrectly, as the highest address of the alternate stack range
Packit 33f14e
         rather than as the lowest address.])
Packit 33f14e
    fi
Packit 33f14e
Packit 33f14e
   AC_CACHE_CHECK([for precise C stack overflow detection],
Packit 33f14e
     ac_cv_sys_xsi_stack_overflow_heuristic,
Packit 33f14e
     [AC_RUN_IFELSE([AC_LANG_SOURCE(
Packit 33f14e
           [[
Packit 33f14e
            #include <unistd.h>
Packit 33f14e
            #include <signal.h>
Packit 33f14e
            #if HAVE_UCONTEXT_H
Packit 33f14e
            # include <ucontext.h>
Packit 33f14e
            #endif
Packit 33f14e
            #if HAVE_SETRLIMIT
Packit 33f14e
            # include <sys/types.h>
Packit 33f14e
            # include <sys/time.h>
Packit 33f14e
            # include <sys/resource.h>
Packit 33f14e
            #endif
Packit 33f14e
            #ifndef SIGSTKSZ
Packit 33f14e
            # define SIGSTKSZ 16384
Packit 33f14e
            #endif
Packit 33f14e
Packit 33f14e
            static union
Packit 33f14e
            {
Packit 33f14e
              char buffer[2 * SIGSTKSZ];
Packit 33f14e
              long double ld;
Packit 33f14e
              long u;
Packit 33f14e
              void *p;
Packit 33f14e
            } alternate_signal_stack;
Packit 33f14e
Packit 33f14e
            #if STACK_DIRECTION
Packit 33f14e
            # define find_stack_direction(ptr) STACK_DIRECTION
Packit 33f14e
            #else
Packit 33f14e
            static int
Packit 33f14e
            find_stack_direction (char const *addr)
Packit 33f14e
            {
Packit 33f14e
              char dummy;
Packit 33f14e
              return (! addr ? find_stack_direction (&dummy)
Packit 33f14e
                      : addr < &dummy ? 1 : -1);
Packit 33f14e
            }
Packit 33f14e
            #endif
Packit 33f14e
Packit 33f14e
            static void
Packit 33f14e
            segv_handler (int signo, siginfo_t *info, void *context)
Packit 33f14e
            {
Packit 33f14e
              if (0 < info->si_code)
Packit 33f14e
                {
Packit 33f14e
                  /* For XSI heuristics to work, we need uc_stack to describe
Packit 33f14e
                     the interrupted stack (as on Solaris), and not the
Packit 33f14e
                     currently executing stack (as on Linux).  */
Packit 33f14e
                  ucontext_t const *user_context = context;
Packit 33f14e
                  char const *stack_min = user_context->uc_stack.ss_sp;
Packit 33f14e
                  size_t stack_size = user_context->uc_stack.ss_size;
Packit 33f14e
                  char const *faulting_address = info->si_addr;
Packit 33f14e
                  size_t s = faulting_address - stack_min;
Packit 33f14e
                  size_t page_size = sysconf (_SC_PAGESIZE);
Packit 33f14e
                  if (find_stack_direction (0) < 0)
Packit 33f14e
                    s += page_size;
Packit 33f14e
                  if (s < stack_size + page_size)
Packit 33f14e
                    _exit (0);
Packit 33f14e
                  _exit (4);
Packit 33f14e
                }
Packit 33f14e
              _exit (5);
Packit 33f14e
            }
Packit 33f14e
Packit 33f14e
            static int
Packit 33f14e
            c_stack_action ()
Packit 33f14e
            {
Packit 33f14e
              stack_t st;
Packit 33f14e
              struct sigaction act;
Packit 33f14e
              int r;
Packit 33f14e
Packit 33f14e
              st.ss_flags = 0;
Packit 33f14e
              /* Use the midpoint to avoid Irix sigaltstack bug.  */
Packit 33f14e
              st.ss_sp = alternate_signal_stack.buffer + SIGSTKSZ;
Packit 33f14e
              st.ss_size = SIGSTKSZ;
Packit 33f14e
              r = sigaltstack (&st, 0);
Packit 33f14e
              if (r != 0)
Packit 33f14e
                return 1;
Packit 33f14e
Packit 33f14e
              sigemptyset (&act.sa_mask);
Packit 33f14e
              act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
Packit 33f14e
              act.sa_sigaction = segv_handler;
Packit 33f14e
              #if FAULT_YIELDS_SIGBUS
Packit 33f14e
              if (sigaction (SIGBUS, &act, 0) < 0)
Packit 33f14e
                return 2;
Packit 33f14e
              #endif
Packit 33f14e
              if (sigaction (SIGSEGV, &act, 0) < 0)
Packit 33f14e
                return 3;
Packit 33f14e
              return 0;
Packit 33f14e
            }
Packit 33f14e
            static volatile int *
Packit 33f14e
            recurse_1 (volatile int n, volatile int *p)
Packit 33f14e
            {
Packit 33f14e
              if (n >= 0)
Packit 33f14e
                *recurse_1 (n + 1, p) += n;
Packit 33f14e
              return p;
Packit 33f14e
            }
Packit 33f14e
            static int
Packit 33f14e
            recurse (volatile int n)
Packit 33f14e
            {
Packit 33f14e
              int sum = 0;
Packit 33f14e
              return *recurse_1 (n, &sum);
Packit 33f14e
            }
Packit 33f14e
            int
Packit 33f14e
            main ()
Packit 33f14e
            {
Packit 33f14e
              int result;
Packit 33f14e
              #if HAVE_SETRLIMIT && defined RLIMIT_STACK
Packit 33f14e
              /* Before starting the endless recursion, try to be friendly
Packit 33f14e
                 to the user's machine.  On some Linux 2.2.x systems, there
Packit 33f14e
                 is no stack limit for user processes at all.  We don't want
Packit 33f14e
                 to kill such systems.  */
Packit 33f14e
              struct rlimit rl;
Packit 33f14e
              rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
Packit 33f14e
              setrlimit (RLIMIT_STACK, &rl);
Packit 33f14e
              #endif
Packit 33f14e
Packit 33f14e
              result = c_stack_action ();
Packit 33f14e
              if (result != 0)
Packit 33f14e
                return result;
Packit 33f14e
              return recurse (0);
Packit 33f14e
            }
Packit 33f14e
           ]])],
Packit 33f14e
        [ac_cv_sys_xsi_stack_overflow_heuristic=yes],
Packit 33f14e
        [ac_cv_sys_xsi_stack_overflow_heuristic=no],
Packit 33f14e
        [ac_cv_sys_xsi_stack_overflow_heuristic=cross-compiling])])
Packit 33f14e
Packit 33f14e
   if test $ac_cv_sys_xsi_stack_overflow_heuristic = yes; then
Packit 33f14e
     AC_DEFINE([HAVE_XSI_STACK_OVERFLOW_HEURISTIC], [1],
Packit 33f14e
       [Define to 1 if extending the stack slightly past the limit causes
Packit 33f14e
        a SIGSEGV, and an alternate stack can be established with sigaltstack,
Packit 33f14e
        and the signal handler is passed a context that specifies the
Packit 33f14e
        run time stack.  This behavior is defined by POSIX 1003.1-2001
Packit 33f14e
        with the X/Open System Interface (XSI) option
Packit 33f14e
        and is a standardized way to implement a SEGV-based stack
Packit 33f14e
        overflow detection heuristic.])
Packit 33f14e
   fi
Packit 33f14e
  fi])
Packit 33f14e
Packit 33f14e
Packit 33f14e
AC_DEFUN([gl_PREREQ_C_STACK],
Packit 33f14e
  [AC_REQUIRE([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC])
Packit 33f14e
   AC_REQUIRE([gl_LIBSIGSEGV])
Packit 33f14e
Packit 33f14e
   # for STACK_DIRECTION
Packit 33f14e
   AC_REQUIRE([AC_FUNC_ALLOCA])
Packit 33f14e
Packit 33f14e
   AC_CHECK_FUNCS_ONCE([sigaltstack])
Packit 33f14e
   AC_CHECK_DECLS([sigaltstack], , , [[#include <signal.h>]])
Packit 33f14e
Packit 33f14e
   AC_CHECK_HEADERS_ONCE([unistd.h ucontext.h])
Packit 33f14e
Packit 33f14e
   AC_CHECK_TYPES([stack_t], , , [#include <signal.h>])
Packit 33f14e
Packit 33f14e
   dnl c-stack does not need -lsigsegv if the system has XSI heuristics.
Packit 33f14e
   if test "$gl_cv_lib_sigsegv" = yes \
Packit 33f14e
       && test $"ac_cv_sys_xsi_stack_overflow_heuristic" != yes ; then
Packit 33f14e
     AC_SUBST([LIBCSTACK], [$LIBSIGSEGV])
Packit 33f14e
     AC_SUBST([LTLIBCSTACK], [$LTLIBSIGSEGV])
Packit 33f14e
   fi
Packit 33f14e
])
Packit 33f14e
Packit 33f14e
AC_DEFUN([gl_C_STACK],
Packit 33f14e
[
Packit 33f14e
  dnl Prerequisites of lib/c-stack.c.
Packit 33f14e
  gl_PREREQ_C_STACK
Packit 33f14e
])