1 # Check prerequisites for compiling lib/c-stack.c.
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.
8 # Written by Paul Eggert.
12 AC_DEFUN([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC],
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 }.
22 sunos4* | freebsd* | dragonfly* | openbsd* | mirbsd* | netbsd* | kfreebsd* | knetbsd*) # BSD systems
23 FAULT_YIELDS_SIGBUS=1 ;;
25 FAULT_YIELDS_SIGBUS=1 ;;
26 macos* | darwin*) # Mac OS X
27 FAULT_YIELDS_SIGBUS=1 ;;
29 FAULT_YIELDS_SIGBUS=1 ;;
31 FAULT_YIELDS_SIGBUS=0 ;;
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(
43 # include <sys/types.h>
44 # include <sys/time.h>
45 # include <sys/resource.h>
48 # define SIGSTKSZ 16384
53 char buffer[2 * SIGSTKSZ];
57 } alternate_signal_stack;
60 segv_handler (int signo)
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);
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)
87 if (sigaction (SIGSEGV, &act, 0) < 0)
92 recurse_1 (volatile int n, volatile int *p)
95 *recurse_1 (n + 1, p) += n;
99 recurse (volatile int n)
102 return *recurse_1 (n, &sum);
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. */
114 rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
115 setrlimit (RLIMIT_STACK, &rl);
118 result = c_stack_action ();
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])])
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
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], [
143 #if HAVE_SYS_SIGNAL_H
144 # include <sys/signal.h>
147 # define SIGSTKSZ 16384
149 volatile char *stack_lower_bound;
150 volatile char *stack_upper_bound;
151 static void check_stack_location (volatile char *addr)
153 if (addr >= stack_lower_bound && addr <= stack_upper_bound)
158 static void stackoverflow_handler (int sig)
161 check_stack_location (&dummy);
165 char mystack[2 * SIGSTKSZ];
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)
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)
182 /* Provoke a SIGSEGV. */
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.])
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(
203 # include <ucontext.h>
206 # include <sys/types.h>
207 # include <sys/time.h>
208 # include <sys/resource.h>
211 # define SIGSTKSZ 16384
216 char buffer[2 * SIGSTKSZ];
220 } alternate_signal_stack;
223 # define find_stack_direction(ptr) STACK_DIRECTION
226 find_stack_direction (char const *addr)
229 return (! addr ? find_stack_direction (&dummy)
230 : addr < &dummy ? 1 : -1);
235 segv_handler (int signo, siginfo_t *info, void *context)
237 if (0 < info->si_code)
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)
250 if (s < stack_size + page_size)
261 struct sigaction act;
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);
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)
279 if (sigaction (SIGSEGV, &act, 0) < 0)
283 static volatile int *
284 recurse_1 (volatile int n, volatile int *p)
287 *recurse_1 (n + 1, p) += n;
291 recurse (volatile int n)
294 return *recurse_1 (n, &sum);
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. */
306 rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
307 setrlimit (RLIMIT_STACK, &rl);
310 result = c_stack_action ();
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])])
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.])
333 AC_DEFUN([gl_PREREQ_C_STACK],
334 [AC_REQUIRE([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC])
335 AC_REQUIRE([gl_LIBSIGSEGV])
337 # for STACK_DIRECTION
338 AC_REQUIRE([AC_FUNC_ALLOCA])
340 AC_CHECK_FUNCS_ONCE([sigaltstack])
341 AC_CHECK_DECLS([sigaltstack], , , [[#include <signal.h>]])
343 AC_CHECK_HEADERS_ONCE([unistd.h ucontext.h])
345 AC_CHECK_TYPES([stack_t], , , [#include <signal.h>])
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])
355 AC_DEFUN([gl_C_STACK],
357 dnl Prerequisites of lib/c-stack.c.