Treat SIGBUS like SIFSEGV on platforms that need it.
[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 8
11
12 AC_DEFUN([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC],
13   [# for STACK_DIRECTION
14    AC_REQUIRE([AC_FUNC_ALLOCA])
15    AC_REQUIRE([AC_CANONICAL_HOST])
16    AC_CHECK_FUNCS_ONCE([setrlimit])
17    AC_CHECK_HEADERS_ONCE([ucontext.h])
18
19    dnl List of signals that are sent when an invalid virtual memory address
20    dnl is accessed, or when the stack overflows.
21    dnl Either { SIGSEGV } or { SIGSEGV, SIGBUS }.
22    case "$host_os" in
23      sunos4* | freebsd* | dragonfly* | openbsd* | netbsd* | kfreebsd* | knetbsd*) # BSD systems
24        FAULT_YIELDS_SIGBUS=1 ;;
25      hpux*) # HP-UX
26        FAULT_YIELDS_SIGBUS=1 ;;
27      macos* | darwin*) # MacOS X
28        FAULT_YIELDS_SIGBUS=1 ;;
29      gnu*) # Hurd
30        FAULT_YIELDS_SIGBUS=1 ;;
31      *)
32        FAULT_YIELDS_SIGBUS=0 ;;
33    esac
34    AC_DEFINE_UNQUOTED([FAULT_YIELDS_SIGBUS], [$FAULT_YIELDS_SIGBUS],
35      [Define to 1 if an invalid memory address access may yield a SIGBUS.])
36
37    AC_CACHE_CHECK([for working C stack overflow detection],
38      [ac_cv_sys_stack_overflow_works],
39      [AC_TRY_RUN(
40         [
41          #include <unistd.h>
42          #include <signal.h>
43          #if HAVE_SETRLIMIT
44          # include <sys/types.h>
45          # include <sys/time.h>
46          # include <sys/resource.h>
47          #endif
48          #ifndef SIGSTKSZ
49          # define SIGSTKSZ 16384
50          #endif
51
52          static union
53          {
54            char buffer[2 * SIGSTKSZ];
55            long double ld;
56            long u;
57            void *p;
58          } alternate_signal_stack;
59
60          static void
61          segv_handler (int signo)
62          {
63            _exit (0);
64          }
65
66          static int
67          c_stack_action ()
68          {
69            stack_t st;
70            struct sigaction act;
71            int r;
72
73            st.ss_flags = 0;
74            /* Use the midpoint to avoid Irix sigaltstack bug.  */
75            st.ss_sp = alternate_signal_stack.buffer + SIGSTKSZ;
76            st.ss_size = SIGSTKSZ;
77            r = sigaltstack (&st, 0);
78            if (r != 0)
79              return r;
80
81            sigemptyset (&act.sa_mask);
82            act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
83            act.sa_handler = segv_handler;
84            #if FAULT_YIELDS_SIGBUS
85            if (sigaction (SIGBUS, &act, 0) < 0)
86              return -1;
87            #endif
88            return sigaction (SIGSEGV, &act, 0);
89          }
90          static volatile int *
91          recurse_1 (volatile int n, volatile int *p)
92          {
93            if (n >= 0)
94              *recurse_1 (n + 1, p) += n;
95            return p;
96          }
97          static int
98          recurse (volatile int n)
99          {
100            int sum = 0;
101            return *recurse_1 (n, &sum);
102          }
103          int
104          main ()
105          {
106            #if HAVE_SETRLIMIT && defined RLIMIT_STACK
107            /* Before starting the endless recursion, try to be friendly
108               to the user's machine.  On some Linux 2.2.x systems, there
109               is no stack limit for user processes at all.  We don't want
110               to kill such systems.  */
111            struct rlimit rl;
112            rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
113            setrlimit (RLIMIT_STACK, &rl);
114            #endif
115
116            return c_stack_action () || recurse (0);
117          }
118         ],
119         [ac_cv_sys_stack_overflow_works=yes],
120         [ac_cv_sys_stack_overflow_works=no],
121         [ac_cv_sys_stack_overflow_works=cross-compiling])])
122
123   if test $ac_cv_sys_stack_overflow_works = yes; then
124    AC_DEFINE([HAVE_STACK_OVERFLOW_HANDLING], [1],
125      [Define to 1 if extending the stack slightly past the limit causes
126       a SIGSEGV which can be handled on an alternate stack established
127       with sigaltstack.])
128
129     dnl The ss_sp field of a stack_t is, according to POSIX, the lowest address
130     dnl of the memory block designated as an alternate stack. But IRIX 5.3
131     dnl interprets it as the highest address!
132     AC_CACHE_CHECK([for correct stack_t interpretation],
133       [gl_cv_sigaltstack_low_base], [
134       AC_RUN_IFELSE([
135         AC_LANG_SOURCE([[
136 #include <stdlib.h>
137 #include <signal.h>
138 #if HAVE_SYS_SIGNAL_H
139 # include <sys/signal.h>
140 #endif
141 #ifndef SIGSTKSZ
142 # define SIGSTKSZ 16384
143 #endif
144 volatile char *stack_lower_bound;
145 volatile char *stack_upper_bound;
146 static void check_stack_location (volatile char *addr)
147 {
148   if (addr >= stack_lower_bound && addr <= stack_upper_bound)
149     exit (0);
150   else
151     exit (1);
152 }
153 static void stackoverflow_handler (int sig)
154 {
155   char dummy;
156   check_stack_location (&dummy);
157 }
158 int main ()
159 {
160   char mystack[2 * SIGSTKSZ];
161   stack_t altstack;
162   struct sigaction action;
163   /* Install the alternate stack.  */
164   altstack.ss_sp = mystack + SIGSTKSZ;
165   altstack.ss_size = SIGSTKSZ;
166   stack_lower_bound = (char *) altstack.ss_sp;
167   stack_upper_bound = (char *) altstack.ss_sp + altstack.ss_size - 1;
168   altstack.ss_flags = 0; /* no SS_DISABLE */
169   if (sigaltstack (&altstack, NULL) < 0)
170     exit (2);
171   /* Install the SIGSEGV handler.  */
172   sigemptyset (&action.sa_mask);
173   action.sa_handler = &stackoverflow_handler;
174   action.sa_flags = SA_ONSTACK;
175   if (sigaction (SIGSEGV, &action, (struct sigaction *) NULL) < 0)
176     exit(3);
177   /* Provoke a SIGSEGV.  */
178   raise (SIGSEGV);
179   exit (3);
180 }]])],
181       [gl_cv_sigaltstack_low_base=yes],
182       [gl_cv_sigaltstack_low_base=no],
183       [gl_cv_sigaltstack_low_base=cross-compiling])])
184    if test "$gl_cv_sigaltstack_low_base" = no; then
185       AC_DEFINE([SIGALTSTACK_SS_REVERSED], [1],
186         [Define if sigaltstack() interprets the stack_t.ss_sp field
187          incorrectly, as the highest address of the alternate stack range
188          rather than as the lowest address.])
189     fi
190
191    AC_CACHE_CHECK([for precise C stack overflow detection],
192      ac_cv_sys_xsi_stack_overflow_heuristic,
193      [AC_TRY_RUN(
194         [
195          #include <unistd.h>
196          #include <signal.h>
197          #if HAVE_UCONTEXT_H
198          # include <ucontext.h>
199          #endif
200          #if HAVE_SETRLIMIT
201          # include <sys/types.h>
202          # include <sys/time.h>
203          # include <sys/resource.h>
204          #endif
205          #ifndef SIGSTKSZ
206          # define SIGSTKSZ 16384
207          #endif
208
209          static union
210          {
211            char buffer[2 * SIGSTKSZ];
212            long double ld;
213            long u;
214            void *p;
215          } alternate_signal_stack;
216
217          #if STACK_DIRECTION
218          # define find_stack_direction(ptr) STACK_DIRECTION
219          #else
220          static int
221          find_stack_direction (char const *addr)
222          {
223            char dummy;
224            return (! addr ? find_stack_direction (&dummy)
225                    : addr < &dummy ? 1 : -1);
226          }
227          #endif
228
229          static void
230          segv_handler (int signo, siginfo_t *info, void *context)
231          {
232            if (0 < info->si_code)
233              {
234                /* For XSI heuristics to work, we need uc_stack to describe
235                   the interrupted stack (as on Solaris), and not the
236                   currently executing stack (as on Linux).  */
237                ucontext_t const *user_context = context;
238                char const *stack_min = user_context->uc_stack.ss_sp;
239                size_t stack_size = user_context->uc_stack.ss_size;
240                char const *faulting_address = info->si_addr;
241                size_t s = faulting_address - stack_min;
242                size_t page_size = sysconf (_SC_PAGESIZE);
243                if (find_stack_direction (0) < 0)
244                  s += page_size;
245                if (s < stack_size + page_size)
246                  _exit (0);
247              }
248
249            _exit (1);
250          }
251
252          static int
253          c_stack_action ()
254          {
255            stack_t st;
256            struct sigaction act;
257            int r;
258
259            st.ss_flags = 0;
260            /* Use the midpoint to avoid Irix sigaltstack bug.  */
261            st.ss_sp = alternate_signal_stack.buffer + SIGSTKSZ;
262            st.ss_size = SIGSTKSZ;
263            r = sigaltstack (&st, 0);
264            if (r != 0)
265              return r;
266
267            sigemptyset (&act.sa_mask);
268            act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
269            act.sa_sigaction = segv_handler;
270            #if FAULT_YIELDS_SIGBUS
271            if (sigaction (SIGBUS, &act, 0) < 0)
272              return -1;
273            #endif
274            return sigaction (SIGSEGV, &act, 0);
275          }
276          static volatile int *
277          recurse_1 (volatile int n, volatile int *p)
278          {
279            if (n >= 0)
280              *recurse_1 (n + 1, p) += n;
281            return p;
282          }
283          static int
284          recurse (volatile int n)
285          {
286            int sum = 0;
287            return *recurse_1 (n, &sum);
288          }
289          int
290          main ()
291          {
292            #if HAVE_SETRLIMIT && defined RLIMIT_STACK
293            /* Before starting the endless recursion, try to be friendly
294               to the user's machine.  On some Linux 2.2.x systems, there
295               is no stack limit for user processes at all.  We don't want
296               to kill such systems.  */
297            struct rlimit rl;
298            rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
299            setrlimit (RLIMIT_STACK, &rl);
300            #endif
301
302            return c_stack_action () || recurse (0);
303          }
304         ],
305         [ac_cv_sys_xsi_stack_overflow_heuristic=yes],
306         [ac_cv_sys_xsi_stack_overflow_heuristic=no],
307         [ac_cv_sys_xsi_stack_overflow_heuristic=cross-compiling])])
308
309    if test $ac_cv_sys_xsi_stack_overflow_heuristic = yes; then
310      AC_DEFINE(HAVE_XSI_STACK_OVERFLOW_HEURISTIC, 1,
311        [Define to 1 if extending the stack slightly past the limit causes
312         a SIGSEGV, and an alternate stack can be established with sigaltstack,
313         and the signal handler is passed a context that specifies the
314         run time stack.  This behavior is defined by POSIX 1003.1-2001
315         with the X/Open System Interface (XSI) option
316         and is a standardized way to implement a SEGV-based stack
317         overflow detection heuristic.])
318    fi
319   fi])
320
321
322 AC_DEFUN([gl_PREREQ_C_STACK],
323   [AC_REQUIRE([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC])
324    AC_REQUIRE([gl_LIBSIGSEGV])
325
326    # for STACK_DIRECTION
327    AC_REQUIRE([AC_FUNC_ALLOCA])
328
329    AC_CHECK_FUNCS_ONCE([sigaltstack])
330    AC_CHECK_DECLS([sigaltstack], , , [#include <signal.h>])
331
332    AC_CHECK_HEADERS_ONCE([unistd.h ucontext.h])
333
334    AC_CHECK_TYPES([stack_t], , , [#include <signal.h>])
335
336    dnl c-stack does not need -lsigsegv if the system has XSI heuristics.
337    if test "$gl_cv_lib_sigsegv" = yes \
338        && test $"ac_cv_sys_xsi_stack_overflow_heuristic" != yes ; then
339      AC_SUBST([LIBCSTACK], [$LIBSIGSEGV])
340      AC_SUBST([LTLIBCSTACK], [$LTLIBSIGSEGV])
341    fi
342 ])
343
344 AC_DEFUN([gl_C_STACK],
345 [
346   dnl Prerequisites of lib/c-stack.c.
347   gl_PREREQ_C_STACK
348 ])