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