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