Fix c-stack.c portability bug on IRIX 5.3.
[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
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2, or (at your option)
8 # any later version.
9
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18 # 02111-1307, USA.
19
20 # Written by Paul Eggert.
21
22 AC_DEFUN([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC],
23   [# for STACK_DIRECTION
24    AC_REQUIRE([AC_FUNC_ALLOCA])
25    AC_CHECK_FUNCS(setrlimit)
26
27    AC_CACHE_CHECK([for working C stack overflow detection],
28      ac_cv_sys_xsi_stack_overflow_heuristic,
29      [AC_TRY_RUN(
30         [
31          #include <unistd.h>
32          #include <signal.h>
33          #include <ucontext.h>
34          #if HAVE_SETRLIMIT
35          # include <sys/types.h>
36          # include <sys/time.h>
37          # include <sys/resource.h>
38          #endif
39
40          static union
41          {
42            char buffer[SIGSTKSZ];
43            long double ld;
44            long u;
45            void *p;
46          } alternate_signal_stack;
47
48          #if STACK_DIRECTION
49          # define find_stack_direction(ptr) STACK_DIRECTION
50          #else
51          static int
52          find_stack_direction (char const *addr)
53          {
54            char dummy;
55            return (! addr ? find_stack_direction (&dummy)
56                    : addr < &dummy ? 1 : -1);
57          }
58          #endif
59
60          static void
61          segv_handler (int signo, siginfo_t *info, void *context)
62          {
63            if (0 < info->si_code)
64              {
65                ucontext_t const *user_context = context;
66                char const *stack_min = user_context->uc_stack.ss_sp;
67                size_t stack_size = user_context->uc_stack.ss_size;
68                char const *faulting_address = info->si_addr;
69                size_t s = faulting_address - stack_min;
70                size_t page_size = sysconf (_SC_PAGESIZE);
71                if (find_stack_direction (0) < 0)
72                  s += page_size;
73                if (s < stack_size + page_size)
74                  _exit (0);
75              }
76
77            _exit (1);
78          }
79
80          static int
81          c_stack_action (void)
82          {
83            stack_t st;
84            struct sigaction act;
85            int r;
86
87            st.ss_flags = 0;
88            st.ss_sp = alternate_signal_stack.buffer;
89            st.ss_size = sizeof alternate_signal_stack.buffer;
90            r = sigaltstack (&st, 0);
91            if (r != 0)
92              return r;
93
94            sigemptyset (&act.sa_mask);
95            act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
96            act.sa_sigaction = segv_handler;
97            return sigaction (SIGSEGV, &act, 0);
98          }
99
100          static int
101          recurse (char *p)
102          {
103            char array[500];
104            array[0] = 1;
105            return *p + recurse (array);
106          }
107
108          int
109          main (void)
110          {
111            #if HAVE_SETRLIMIT && defined RLIMIT_STACK
112            /* Before starting the endless recursion, try to be friendly
113               to the user's machine.  On some Linux 2.2.x systems, there
114               is no stack limit for user processes at all.  We don't want
115               to kill such systems.  */
116            struct rlimit rl;
117            rl.rlim_cur = rl.rlim_max = 0x100000; /* 1 MB */
118            setrlimit (RLIMIT_STACK, &rl);
119            #endif
120
121            c_stack_action ();
122            return recurse ("\1");
123          }
124         ],
125         [ac_cv_sys_xsi_stack_overflow_heuristic=yes],
126         [ac_cv_sys_xsi_stack_overflow_heuristic=no],
127         [ac_cv_sys_xsi_stack_overflow_heuristic=cross-compiling])])
128
129    if test $ac_cv_sys_xsi_stack_overflow_heuristic = yes; then
130      AC_DEFINE(HAVE_XSI_STACK_OVERFLOW_HEURISTIC, 1,
131        [Define to 1 if extending the stack slightly past the limit causes
132         a SIGSEGV, and an alternate stack can be established with sigaltstack,
133         and the signal handler is passed a context that specifies the
134         run time stack.  This behavior is defined by POSIX 1003.1-2001
135         with the X/Open System Interface (XSI) option
136         and is a standardized way to implement a SEGV-based stack
137         overflow detection heuristic.])
138    fi])
139
140
141 AC_DEFUN([gl_PREREQ_C_STACK],
142   [AC_REQUIRE([AC_SYS_XSI_STACK_OVERFLOW_HEURISTIC])
143
144    # for STACK_DIRECTION
145    AC_REQUIRE([AC_FUNC_ALLOCA])
146
147    AC_CHECK_FUNCS(getcontext sigaltstack)
148    AC_CHECK_DECLS([getcontext], , , [#include <ucontext.h>])
149    AC_CHECK_DECLS([sigaltstack], , , [#include <signal.h>])
150
151    AC_CHECK_HEADERS_ONCE(sys/time.h unistd.h)
152    AC_CHECK_HEADERS(sys/resource.h ucontext.h)
153
154    AC_CHECK_MEMBERS([struct sigaction.sa_sigaction], , , [#include <signal.h>])
155
156    AC_CHECK_TYPES([stack_t], , , [#include <signal.h>])])
157
158 AC_DEFUN([gl_C_STACK],
159 [
160   dnl Prerequisites of lib/c-stack.c.
161   gl_PREREQ_C_STACK
162 ])