Doc tweak.
[gnulib.git] / m4 / c-stack.m4
1 # Check prerequisites for compiling lib/c-stack.c.
2
3 # Copyright (C) 2002, 2003, 2004, 2008 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 6
11
12 AC_DEFUN([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC],
13   [# for STACK_DIRECTION
14    AC_REQUIRE([AC_FUNC_ALLOCA])
15    AC_CHECK_FUNCS_ONCE([setrlimit])
16    AC_CHECK_HEADERS_ONCE([ucontext.h])
17
18    AC_CACHE_CHECK([for working C stack overflow detection],
19      [ac_cv_sys_stack_overflow_works],
20      [AC_TRY_RUN(
21         [
22          #include <unistd.h>
23          #include <signal.h>
24          #if HAVE_SETRLIMIT
25          # include <sys/types.h>
26          # include <sys/time.h>
27          # include <sys/resource.h>
28          #endif
29          #ifndef SIGSTKSZ
30          # define SIGSTKSZ 16384
31          #endif
32
33          static union
34          {
35            char buffer[SIGSTKSZ];
36            long double ld;
37            long u;
38            void *p;
39          } alternate_signal_stack;
40
41          static void
42          segv_handler (int signo)
43          {
44            _exit (0);
45          }
46
47          static int
48          c_stack_action ()
49          {
50            stack_t st;
51            struct sigaction act;
52            int r;
53
54            st.ss_flags = 0;
55            st.ss_sp = alternate_signal_stack.buffer;
56            st.ss_size = sizeof alternate_signal_stack.buffer;
57            r = sigaltstack (&st, 0);
58            if (r != 0)
59              return r;
60
61            sigemptyset (&act.sa_mask);
62            act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND;
63            act.sa_handler = segv_handler;
64            return sigaction (SIGSEGV, &act, 0);
65          }
66
67          static int
68          recurse (char *p)
69          {
70            char array[500];
71            array[0] = 1;
72            return *p + recurse (array);
73          }
74
75          int
76          main ()
77          {
78            #if HAVE_SETRLIMIT && defined RLIMIT_STACK
79            /* Before starting the endless recursion, try to be friendly
80               to the user's machine.  On some Linux 2.2.x systems, there
81               is no stack limit for user processes at all.  We don't want
82               to kill such systems.  */
83            struct rlimit rl;
84            rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
85            setrlimit (RLIMIT_STACK, &rl);
86            #endif
87
88            return c_stack_action () || recurse ("\1");
89          }
90         ],
91         [ac_cv_sys_stack_overflow_works=yes],
92         [ac_cv_sys_stack_overflow_works=no],
93         [ac_cv_sys_stack_overflow_works=cross-compiling])])
94
95   if test $ac_cv_sys_stack_overflow_works = yes; then
96    AC_DEFINE([HAVE_STACK_OVERFLOW_HANDLING], [1],
97      [Define to 1 if extending the stack slightly past the limit causes
98       a SIGSEGV which can be handled on an alternate stack established
99       with sigaltstack.])
100
101    AC_CACHE_CHECK([for precise C stack overflow detection],
102      ac_cv_sys_xsi_stack_overflow_heuristic,
103      [AC_TRY_RUN(
104         [
105          #include <unistd.h>
106          #include <signal.h>
107          #if HAVE_UCONTEXT_H
108          # include <ucontext.h>
109          #endif
110          #if HAVE_SETRLIMIT
111          # include <sys/types.h>
112          # include <sys/time.h>
113          # include <sys/resource.h>
114          #endif
115          #ifndef SIGSTKSZ
116          # define SIGSTKSZ 16384
117          #endif
118
119          static union
120          {
121            char buffer[SIGSTKSZ];
122            long double ld;
123            long u;
124            void *p;
125          } alternate_signal_stack;
126
127          #if STACK_DIRECTION
128          # define find_stack_direction(ptr) STACK_DIRECTION
129          #else
130          static int
131          find_stack_direction (char const *addr)
132          {
133            char dummy;
134            return (! addr ? find_stack_direction (&dummy)
135                    : addr < &dummy ? 1 : -1);
136          }
137          #endif
138
139          static void
140          segv_handler (int signo, siginfo_t *info, void *context)
141          {
142            if (0 < info->si_code)
143              {
144                /* For XSI heuristics to work, we need uc_stack to describe
145                   the interrupted stack (as on Solaris), and not the
146                   currently executing stack (as on Linux).  */
147                ucontext_t const *user_context = context;
148                char const *stack_min = user_context->uc_stack.ss_sp;
149                size_t stack_size = user_context->uc_stack.ss_size;
150                char const *faulting_address = info->si_addr;
151                size_t s = faulting_address - stack_min;
152                size_t page_size = sysconf (_SC_PAGESIZE);
153                if (find_stack_direction (0) < 0)
154                  s += page_size;
155                if (s < stack_size + page_size)
156                  _exit (0);
157              }
158
159            _exit (1);
160          }
161
162          static int
163          c_stack_action ()
164          {
165            stack_t st;
166            struct sigaction act;
167            int r;
168
169            st.ss_flags = 0;
170            st.ss_sp = alternate_signal_stack.buffer;
171            st.ss_size = sizeof alternate_signal_stack.buffer;
172            r = sigaltstack (&st, 0);
173            if (r != 0)
174              return r;
175
176            sigemptyset (&act.sa_mask);
177            act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
178            act.sa_sigaction = segv_handler;
179            return sigaction (SIGSEGV, &act, 0);
180          }
181
182          static int
183          recurse (char *p)
184          {
185            char array[500];
186            array[0] = 1;
187            return *p + recurse (array);
188          }
189
190          int
191          main ()
192          {
193            #if HAVE_SETRLIMIT && defined RLIMIT_STACK
194            /* Before starting the endless recursion, try to be friendly
195               to the user's machine.  On some Linux 2.2.x systems, there
196               is no stack limit for user processes at all.  We don't want
197               to kill such systems.  */
198            struct rlimit rl;
199            rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
200            setrlimit (RLIMIT_STACK, &rl);
201            #endif
202
203            return c_stack_action () || recurse ("\1");
204          }
205         ],
206         [ac_cv_sys_xsi_stack_overflow_heuristic=yes],
207         [ac_cv_sys_xsi_stack_overflow_heuristic=no],
208         [ac_cv_sys_xsi_stack_overflow_heuristic=cross-compiling])])
209
210    if test $ac_cv_sys_xsi_stack_overflow_heuristic = yes; then
211      AC_DEFINE(HAVE_XSI_STACK_OVERFLOW_HEURISTIC, 1,
212        [Define to 1 if extending the stack slightly past the limit causes
213         a SIGSEGV, and an alternate stack can be established with sigaltstack,
214         and the signal handler is passed a context that specifies the
215         run time stack.  This behavior is defined by POSIX 1003.1-2001
216         with the X/Open System Interface (XSI) option
217         and is a standardized way to implement a SEGV-based stack
218         overflow detection heuristic.])
219    fi
220   fi])
221
222
223 AC_DEFUN([gl_PREREQ_C_STACK],
224   [AC_REQUIRE([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC])
225    AC_REQUIRE([gl_LIBSIGSEGV])
226
227    # for STACK_DIRECTION
228    AC_REQUIRE([AC_FUNC_ALLOCA])
229
230    AC_CHECK_FUNCS_ONCE([sigaltstack])
231    AC_CHECK_DECLS([sigaltstack], , , [#include <signal.h>])
232
233    AC_CHECK_HEADERS_ONCE([unistd.h ucontext.h])
234
235    AC_CHECK_TYPES([stack_t], , , [#include <signal.h>])
236
237    dnl c-stack does not need -lsigsegv if the system has XSI heuristics.
238    if test "$gl_cv_lib_sigsegv" = yes \
239        && test $"ac_cv_sys_xsi_stack_overflow_heuristic" != yes ; then
240      AC_SUBST([LIBCSTACK], [$LIBSIGSEGV])
241      AC_SUBST([LTLIBCSTACK], [$LTLIBSIGSEGV])
242    fi
243 ])
244
245 AC_DEFUN([gl_C_STACK],
246 [
247   dnl Prerequisites of lib/c-stack.c.
248   gl_PREREQ_C_STACK
249 ])