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