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