Use an all-permissive copyright notice, recommended by RMS.
[gnulib.git] / m4 / c-stack.m4
1 # Check prerequisites for compiling lib/c-stack.c.
2
3 # Copyright (C) 2002, 2003, 2004 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 AC_DEFUN([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC],
11   [# for STACK_DIRECTION
12    AC_REQUIRE([AC_FUNC_ALLOCA])
13    AC_CHECK_FUNCS(setrlimit)
14
15    AC_CACHE_CHECK([for working C stack overflow detection],
16      ac_cv_sys_xsi_stack_overflow_heuristic,
17      [AC_TRY_RUN(
18         [
19          #include <unistd.h>
20          #include <signal.h>
21          #include <ucontext.h>
22          #if HAVE_SETRLIMIT
23          # include <sys/types.h>
24          # include <sys/time.h>
25          # include <sys/resource.h>
26          #endif
27
28          static union
29          {
30            char buffer[SIGSTKSZ];
31            long double ld;
32            long u;
33            void *p;
34          } alternate_signal_stack;
35
36          #if STACK_DIRECTION
37          # define find_stack_direction(ptr) STACK_DIRECTION
38          #else
39          static int
40          find_stack_direction (char const *addr)
41          {
42            char dummy;
43            return (! addr ? find_stack_direction (&dummy)
44                    : addr < &dummy ? 1 : -1);
45          }
46          #endif
47
48          static void
49          segv_handler (int signo, siginfo_t *info, void *context)
50          {
51            if (0 < info->si_code)
52              {
53                ucontext_t const *user_context = context;
54                char const *stack_min = user_context->uc_stack.ss_sp;
55                size_t stack_size = user_context->uc_stack.ss_size;
56                char const *faulting_address = info->si_addr;
57                size_t s = faulting_address - stack_min;
58                size_t page_size = sysconf (_SC_PAGESIZE);
59                if (find_stack_direction (0) < 0)
60                  s += page_size;
61                if (s < stack_size + page_size)
62                  _exit (0);
63              }
64
65            _exit (1);
66          }
67
68          static int
69          c_stack_action (void)
70          {
71            stack_t st;
72            struct sigaction act;
73            int r;
74
75            st.ss_flags = 0;
76            st.ss_sp = alternate_signal_stack.buffer;
77            st.ss_size = sizeof alternate_signal_stack.buffer;
78            r = sigaltstack (&st, 0);
79            if (r != 0)
80              return r;
81
82            sigemptyset (&act.sa_mask);
83            act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
84            act.sa_sigaction = segv_handler;
85            return sigaction (SIGSEGV, &act, 0);
86          }
87
88          static int
89          recurse (char *p)
90          {
91            char array[500];
92            array[0] = 1;
93            return *p + recurse (array);
94          }
95
96          int
97          main (void)
98          {
99            #if HAVE_SETRLIMIT && defined RLIMIT_STACK
100            /* Before starting the endless recursion, try to be friendly
101               to the user's machine.  On some Linux 2.2.x systems, there
102               is no stack limit for user processes at all.  We don't want
103               to kill such systems.  */
104            struct rlimit rl;
105            rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
106            setrlimit (RLIMIT_STACK, &rl);
107            #endif
108
109            c_stack_action ();
110            return recurse ("\1");
111          }
112         ],
113         [ac_cv_sys_xsi_stack_overflow_heuristic=yes],
114         [ac_cv_sys_xsi_stack_overflow_heuristic=no],
115         [ac_cv_sys_xsi_stack_overflow_heuristic=cross-compiling])])
116
117    if test $ac_cv_sys_xsi_stack_overflow_heuristic = yes; then
118      AC_DEFINE(HAVE_XSI_STACK_OVERFLOW_HEURISTIC, 1,
119        [Define to 1 if extending the stack slightly past the limit causes
120         a SIGSEGV, and an alternate stack can be established with sigaltstack,
121         and the signal handler is passed a context that specifies the
122         run time stack.  This behavior is defined by POSIX 1003.1-2001
123         with the X/Open System Interface (XSI) option
124         and is a standardized way to implement a SEGV-based stack
125         overflow detection heuristic.])
126    fi])
127
128
129 AC_DEFUN([gl_PREREQ_C_STACK],
130   [AC_REQUIRE([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC])
131
132    # for STACK_DIRECTION
133    AC_REQUIRE([AC_FUNC_ALLOCA])
134
135    AC_CHECK_FUNCS(getcontext sigaltstack)
136    AC_CHECK_DECLS([getcontext], , , [#include <ucontext.h>])
137    AC_CHECK_DECLS([sigaltstack], , , [#include <signal.h>])
138
139    AC_CHECK_HEADERS_ONCE(sys/time.h unistd.h)
140    AC_CHECK_HEADERS(sys/resource.h ucontext.h)
141
142    AC_CHECK_MEMBERS([struct sigaction.sa_sigaction], , , [#include <signal.h>])
143
144    AC_CHECK_TYPES([stack_t], , , [#include <signal.h>])])
145
146 AC_DEFUN([gl_C_STACK],
147 [
148   dnl Prerequisites of lib/c-stack.c.
149   gl_PREREQ_C_STACK
150 ])