Make c-stack use libsigsegv, when available.
[gnulib.git] / m4 / c-stack.m4
1 # Check prerequisites for compiling lib/c-stack.c.
2
3 # Copyright (C) 2002, 2003, 2004, 2008 Free Software Foundation, Inc.
4 # This file is free software; the Free Software Foundation
5 # gives unlimited permission to copy and/or distribute it,
6 # with or without modifications, as long as this notice is preserved.
7
8 # Written by Paul Eggert.
9
10 # serial 3
11
12 AC_DEFUN([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC],
13   [# for STACK_DIRECTION
14    AC_REQUIRE([AC_FUNC_ALLOCA])
15    AC_CHECK_FUNCS_ONCE([setrlimit])
16    AC_CHECK_HEADERS_ONCE([ucontext.h])
17
18    AC_CACHE_CHECK([for working C stack overflow detection],
19      ac_cv_sys_xsi_stack_overflow_heuristic,
20      [AC_TRY_RUN(
21         [
22          #include <unistd.h>
23          #include <signal.h>
24          #if HAVE_UCONTEXT_H
25          # include <ucontext.h>
26          #endif
27          #if HAVE_SETRLIMIT
28          # include <sys/types.h>
29          # include <sys/time.h>
30          # include <sys/resource.h>
31          #endif
32
33          static union
34          {
35            char buffer[SIGSTKSZ];
36            long double ld;
37            long u;
38            void *p;
39          } alternate_signal_stack;
40
41          #if STACK_DIRECTION
42          # define find_stack_direction(ptr) STACK_DIRECTION
43          #else
44          static int
45          find_stack_direction (char const *addr)
46          {
47            char dummy;
48            return (! addr ? find_stack_direction (&dummy)
49                    : addr < &dummy ? 1 : -1);
50          }
51          #endif
52
53          static void
54          segv_handler (int signo, siginfo_t *info, void *context)
55          {
56            if (0 < info->si_code)
57              {
58                /* For XSI heuristics to work, we need uc_stack to describe
59                   the interrupted stack (as on Solaris), and not the
60                   currently executing stack (as on Linux).  */
61                ucontext_t const *user_context = context;
62                char const *stack_min = user_context->uc_stack.ss_sp;
63                size_t stack_size = user_context->uc_stack.ss_size;
64                char const *faulting_address = info->si_addr;
65                size_t s = faulting_address - stack_min;
66                size_t page_size = sysconf (_SC_PAGESIZE);
67                if (find_stack_direction (0) < 0)
68                  s += page_size;
69                if (s < stack_size + page_size)
70                  _exit (0);
71              }
72
73            _exit (1);
74          }
75
76          static int
77          c_stack_action ()
78          {
79            stack_t st;
80            struct sigaction act;
81            int r;
82
83            st.ss_flags = 0;
84            st.ss_sp = alternate_signal_stack.buffer;
85            st.ss_size = sizeof alternate_signal_stack.buffer;
86            r = sigaltstack (&st, 0);
87            if (r != 0)
88              return r;
89
90            sigemptyset (&act.sa_mask);
91            act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
92            act.sa_sigaction = segv_handler;
93            return sigaction (SIGSEGV, &act, 0);
94          }
95
96          static int
97          recurse (char *p)
98          {
99            char array[500];
100            array[0] = 1;
101            return *p + recurse (array);
102          }
103
104          int
105          main ()
106          {
107            #if HAVE_SETRLIMIT && defined RLIMIT_STACK
108            /* Before starting the endless recursion, try to be friendly
109               to the user's machine.  On some Linux 2.2.x systems, there
110               is no stack limit for user processes at all.  We don't want
111               to kill such systems.  */
112            struct rlimit rl;
113            rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
114            setrlimit (RLIMIT_STACK, &rl);
115            #endif
116
117            c_stack_action ();
118            return recurse ("\1");
119          }
120         ],
121         [ac_cv_sys_xsi_stack_overflow_heuristic=yes],
122         [ac_cv_sys_xsi_stack_overflow_heuristic=no],
123         [ac_cv_sys_xsi_stack_overflow_heuristic=cross-compiling])])
124
125    if test $ac_cv_sys_xsi_stack_overflow_heuristic = yes; then
126      AC_DEFINE(HAVE_XSI_STACK_OVERFLOW_HEURISTIC, 1,
127        [Define to 1 if extending the stack slightly past the limit causes
128         a SIGSEGV, and an alternate stack can be established with sigaltstack,
129         and the signal handler is passed a context that specifies the
130         run time stack.  This behavior is defined by POSIX 1003.1-2001
131         with the X/Open System Interface (XSI) option
132         and is a standardized way to implement a SEGV-based stack
133         overflow detection heuristic.])
134    fi])
135
136
137 AC_DEFUN([gl_PREREQ_C_STACK],
138   [AC_REQUIRE([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC])
139    AC_REQUIRE([gl_LIBSIGSEGV])
140
141    # for STACK_DIRECTION
142    AC_REQUIRE([AC_FUNC_ALLOCA])
143
144    AC_CHECK_FUNCS_ONCE([sigaltstack])
145    AC_CHECK_DECLS([sigaltstack], , , [#include <signal.h>])
146
147    AC_CHECK_HEADERS_ONCE([unistd.h ucontext.h])
148
149    AC_CHECK_MEMBERS([struct sigaction.sa_sigaction], , , [#include <signal.h>])
150
151    AC_CHECK_TYPES([stack_t], , , [#include <signal.h>])
152
153    dnl c-stack does not need -lsigsegv if the system has XSI heuristics.
154    if test "$gl_cv_lib_sigsegv" = yes \
155        && test $"ac_cv_sys_xsi_stack_overflow_heuristic" != yes ; then
156      AC_SUBST([LIBCSTACK], [$LIBSIGSEGV])
157      AC_SUBST([LTLIBCSTACK], [$LTLIBSIGSEGV])
158    fi
159 ])
160
161 AC_DEFUN([gl_C_STACK],
162 [
163   dnl Prerequisites of lib/c-stack.c.
164   gl_PREREQ_C_STACK
165 ])