f210842fda40cfefb454a4cb1d3d5dd36e89e936
[platform/upstream/diffutils.git] / m4 / c-stack.m4
1 # Check prerequisites for compiling lib/c-stack.c.
2
3 # Copyright (C) 2002-2004, 2008-2018 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 17
11
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])
17
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.])
35
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
50
51             static union
52             {
53               char buffer[2 * SIGSTKSZ];
54               long double ld;
55               long u;
56               void *p;
57             } alternate_signal_stack;
58
59             static void
60             segv_handler (int signo)
61             {
62               _exit (0);
63             }
64
65             static int
66             c_stack_action ()
67             {
68               stack_t st;
69               struct sigaction act;
70               int r;
71
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;
79
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
117
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      ])
133
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.])
139
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)
158 {
159   if (addr >= stack_lower_bound && addr <= stack_upper_bound)
160     exit (0);
161   else
162     exit (1);
163 }
164 static void stackoverflow_handler (int sig)
165 {
166   char dummy;
167   check_stack_location (&dummy);
168 }
169 int main ()
170 {
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
201
202    AC_CACHE_CHECK([for precise C stack overflow detection],
203      [ac_cv_sys_xsi_stack_overflow_heuristic],
204      [dnl On Linux/sparc64 (both in 32-bit and 64-bit mode), it would be wrong
205       dnl to set HAVE_XSI_STACK_OVERFLOW_HEURISTIC to 1, because the third
206       dnl argument passed to the segv_handler is a 'struct sigcontext *', not
207       dnl an 'ucontext_t *'.  It would lead to a failure of test-c-stack2.sh.
208       case "${host_os}--${host_cpu}" in
209         linux*--sparc*)
210           ac_cv_sys_xsi_stack_overflow_heuristic=no
211           ;;
212         *)
213           AC_RUN_IFELSE(
214             [AC_LANG_SOURCE(
215                [[
216                 #include <unistd.h>
217                 #include <signal.h>
218                 #if HAVE_UCONTEXT_H
219                 # include <ucontext.h>
220                 #endif
221                 #if HAVE_SETRLIMIT
222                 # include <sys/types.h>
223                 # include <sys/time.h>
224                 # include <sys/resource.h>
225                 #endif
226                 #ifndef SIGSTKSZ
227                 # define SIGSTKSZ 16384
228                 #endif
229
230                 static union
231                 {
232                   char buffer[2 * SIGSTKSZ];
233                   long double ld;
234                   long u;
235                   void *p;
236                 } alternate_signal_stack;
237
238                 #if STACK_DIRECTION
239                 # define find_stack_direction(ptr) STACK_DIRECTION
240                 #else
241                 static int
242                 find_stack_direction (char const *addr)
243                 {
244                   char dummy;
245                   return (! addr ? find_stack_direction (&dummy)
246                           : addr < &dummy ? 1 : -1);
247                 }
248                 #endif
249
250                 static void
251                 segv_handler (int signo, siginfo_t *info, void *context)
252                 {
253                   if (0 < info->si_code)
254                     {
255                       /* For XSI heuristics to work, we need uc_stack to
256                          describe the interrupted stack (as on Solaris), and
257                          not the currently executing stack (as on Linux).  */
258                       ucontext_t const *user_context = context;
259                       char const *stack_min = user_context->uc_stack.ss_sp;
260                       size_t stack_size = user_context->uc_stack.ss_size;
261                       char const *faulting_address = info->si_addr;
262                       size_t s = faulting_address - stack_min;
263                       size_t page_size = sysconf (_SC_PAGESIZE);
264                       if (find_stack_direction (0) < 0)
265                         s += page_size;
266                       if (s < stack_size + page_size)
267                         _exit (0);
268                       _exit (4);
269                     }
270                   _exit (5);
271                 }
272
273                 static int
274                 c_stack_action ()
275                 {
276                   stack_t st;
277                   struct sigaction act;
278                   int r;
279
280                   st.ss_flags = 0;
281                   /* Use the midpoint to avoid Irix sigaltstack bug.  */
282                   st.ss_sp = alternate_signal_stack.buffer + SIGSTKSZ;
283                   st.ss_size = SIGSTKSZ;
284                   r = sigaltstack (&st, 0);
285                   if (r != 0)
286                     return 1;
287
288                   sigemptyset (&act.sa_mask);
289                   act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
290                   act.sa_sigaction = segv_handler;
291                   #if FAULT_YIELDS_SIGBUS
292                   if (sigaction (SIGBUS, &act, 0) < 0)
293                     return 2;
294                   #endif
295                   if (sigaction (SIGSEGV, &act, 0) < 0)
296                     return 3;
297                   return 0;
298                 }
299                 static volatile int *
300                 recurse_1 (volatile int n, volatile int *p)
301                 {
302                   if (n >= 0)
303                     *recurse_1 (n + 1, p) += n;
304                   return p;
305                 }
306                 static int
307                 recurse (volatile int n)
308                 {
309                   int sum = 0;
310                   return *recurse_1 (n, &sum);
311                 }
312                 int
313                 main ()
314                 {
315                   int result;
316                   #if HAVE_SETRLIMIT && defined RLIMIT_STACK
317                   /* Before starting the endless recursion, try to be friendly
318                      to the user's machine.  On some Linux 2.2.x systems, there
319                      is no stack limit for user processes at all.  We don't want
320                      to kill such systems.  */
321                   struct rlimit rl;
322                   rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
323                   setrlimit (RLIMIT_STACK, &rl);
324                   #endif
325
326                   result = c_stack_action ();
327                   if (result != 0)
328                     return result;
329                   return recurse (0);
330                 }
331                ]])],
332             [ac_cv_sys_xsi_stack_overflow_heuristic=yes],
333             [ac_cv_sys_xsi_stack_overflow_heuristic=no],
334             [ac_cv_sys_xsi_stack_overflow_heuristic=cross-compiling])
335           ;;
336       esac
337      ])
338
339    if test $ac_cv_sys_xsi_stack_overflow_heuristic = yes; then
340      AC_DEFINE([HAVE_XSI_STACK_OVERFLOW_HEURISTIC], [1],
341        [Define to 1 if extending the stack slightly past the limit causes
342         a SIGSEGV, and an alternate stack can be established with sigaltstack,
343         and the signal handler is passed a context that specifies the
344         run time stack.  This behavior is defined by POSIX 1003.1-2001
345         with the X/Open System Interface (XSI) option
346         and is a standardized way to implement a SEGV-based stack
347         overflow detection heuristic.])
348    fi
349   fi])
350
351
352 AC_DEFUN([gl_PREREQ_C_STACK],
353   [AC_REQUIRE([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC])
354    AC_REQUIRE([gl_LIBSIGSEGV])
355
356    # for STACK_DIRECTION
357    AC_REQUIRE([AC_FUNC_ALLOCA])
358
359    AC_CHECK_FUNCS_ONCE([sigaltstack])
360    AC_CHECK_DECLS([sigaltstack], , , [[#include <signal.h>]])
361
362    AC_CHECK_HEADERS_ONCE([unistd.h ucontext.h])
363
364    AC_CHECK_TYPES([stack_t], , , [#include <signal.h>])
365
366    dnl c-stack does not need -lsigsegv if the system has XSI heuristics.
367    if test "$gl_cv_lib_sigsegv" = yes \
368        && test $"ac_cv_sys_xsi_stack_overflow_heuristic" != yes ; then
369      AC_SUBST([LIBCSTACK], [$LIBSIGSEGV])
370      AC_SUBST([LTLIBCSTACK], [$LTLIBSIGSEGV])
371    fi
372 ])
373
374 AC_DEFUN([gl_C_STACK],
375 [
376   dnl Prerequisites of lib/c-stack.c.
377   gl_PREREQ_C_STACK
378 ])