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