maint: run update-copyright for 2014.
[m4/ericb.git] / src / stackovf.c
blob4810019b7a7618b8a97219851fd00d3441771807
1 /* Detect stack overflow (when getrlimit and sigaction or sigvec are available)
2 Copyright (C) 1993-1994, 2006-2007, 2010, 2013-2014 Free Software
3 Foundation, Inc.
4 Jim Avera <jima@netcom.com>, October 1993.
6 This file is part of GNU M4.
8 GNU M4 is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 GNU M4 is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 /* Compiled only when USE_STACKOVF is defined, which itself requires
23 getrlimit with the RLIMIT_STACK option, and support for alternate
24 signal stacks using either SVR4 or BSD interfaces.
26 This should compile on ANY system which supports either sigaltstack()
27 or sigstack(), with or without <siginfo.h> or another way to determine
28 the fault address.
30 There is no completely portable way to determine if a SIGSEGV signal
31 indicates a stack overflow. The fault address can be used to infer
32 this. However, the fault address is passed to the signal handler in
33 different ways on various systems. One of three methods are used to
34 determine the fault address:
36 1. The siginfo parameter (with siginfo.h, i.e., SVR4).
38 2. 4th "addr" parameter (assumed if struct sigcontext is defined,
39 i.e., SunOS 4.x/BSD).
41 3. None (if no method is available). This case just prints a
42 message before aborting with a core dump. That way the user at
43 least knows that it *might* be a recursion problem.
45 Jim Avera <jima@netcom.com> writes, on Tue, 5 Oct 93 19:27 PDT:
47 "I got interested finding out how a program could catch and
48 diagnose its own stack overflow, and ended up modifying m4 to do
49 this. Now it prints a nice error message and exits.
51 How it works: SIGSEGV is caught using a separate signal stack. The
52 signal handler declares a stack overflow if the fault address is
53 near the end of the stack region, or if the maximum VM address
54 space limit has been reached. Otherwise, it returns to re-execute
55 the instruction with SIG_DFL set, so that any real bugs cause a
56 core dump as usual."
58 Jim Avera <jima@netcom.com> writes, on Fri, 24 Jun 94 12:14 PDT:
60 "The stack-overflow detection code would still be needed to avoid a
61 SIGSEGV abort if swap space was exhausted at the moment the stack
62 tried to grow. This is probably unlikely to occur with the
63 explicit nesting limit option of GNU m4."
65 Jim Avera <jima@netcom.com> writes, on Wed, 6 Jul 1994 14:41 PDT:
67 "When a stack overflow occurs, a SIGSEGV signal is sent, which by
68 default aborts the process with a core dump.
70 The code in stackovf.c catches SIGSEGV using a separate signal
71 stack. The signal handler determines whether or not the SIGSEGV
72 arose from a stack overflow. If it is a stack overflow, an
73 external function is called (which, in m4, prints a message an
74 exits). Otherwise the SIGSEGV represents an m4 bug, and the signal
75 is re-raised with SIG_DFL set, which results in an abort and core
76 dump in the usual way. It seems important (to me) that internal m4
77 bugs not be reported as user recursion errors, or vice-versa." */
79 /* Define this to see runtime debug info. Implied by DEBUG. */
80 /*#define DEBUG_STKOVF */
82 #include <config.h>
84 #include "m4.h"
86 #ifdef USE_STACKOVF
88 #include <sys/time.h>
89 #include <sys/resource.h>
91 #if HAVE_SIGINFO_H
92 # include <siginfo.h>
93 #endif
95 #ifndef SA_RESETHAND
96 # define SA_RESETHAND 0
97 #endif
98 #ifndef SA_SIGINFO
99 # define SA_SIGINFO 0
100 #endif
102 #ifndef SIGSTKSZ
103 # define SIGSTKSZ 8192
104 #endif
106 /* If the trap address is within STACKOVF_DETECT bytes of the calculated
107 stack limit, we diagnose a stack overflow. This must be large enough
108 to cover errors in our estimatation of the limit address, and to
109 account for the maximum size of local variables (the amount the
110 trapping reference might exceed the stack limit). Also, some machines
111 may report an arbitrary address within the same page frame.
112 If the value is too large, we might call some other SIGSEGV a stack
113 overflow, masking a bug. */
115 #ifndef STACKOVF_DETECT
116 # define STACKOVF_DETECT 16384
117 #endif
119 typedef void (*handler_t) (void);
121 #if defined __ultrix && defined __vax
122 extern char *sbrk (int);
123 extern int getrlimit (int, struct rlimit *);
124 extern int sigstack (struct sigstack *, struct sigstack *);
125 extern int sigvec (int, struct sigvec *, struct sigvec *);
126 #endif
128 static void *stackbuf;
129 static const char *stackbot;
130 static const char *stackend;
131 static const char *arg0;
132 static handler_t stackovf_handler;
134 /* The following OS-independent procedure is called from the SIGSEGV
135 signal handler. The signal handler obtains information about the trap
136 in an OS-dependent manner, and passes a parameter with the meanings as
137 explained below.
139 If the OS explicitly identifies a stack overflow trap, either pass
140 PARAM_STACKOVF if a stack overflow, or pass PARAM_NOSTACKOVF if not
141 (id est, it is a random bounds violation). Otherwise, if the fault
142 address is available, pass the fault address. Otherwise (if no
143 information is available), pass NULL.
145 Not given an explicit indication, we compare the fault address with
146 the estimated stack limit, and test to see if overall VM space is
147 exhausted.
149 If a stack overflow is identified, then the external *stackovf_handler
150 function is called, which should print an error message and exit. If
151 it is NOT a stack overflow, then we silently abort with a core dump by
152 returning to re-raise the SIGSEGV with SIG_DFL set. If indeterminate,
153 then we do not call *stackovf_handler, but instead print an ambiguous
154 message and abort with a core dump. This only occurs on systems which
155 provide no information, but is better than nothing. */
157 #define PARAM_STACKOVF ((const char *) (1 + STACKOVF_DETECT))
158 #define PARAM_NOSTACKOVF ((const char *) (2 + STACKOVF_DETECT))
160 static void
161 process_sigsegv (int signo, const char *p)
163 ptrdiff_t diff;
164 diff = (p - stackend);
166 #ifdef DEBUG_STKOVF
168 char buf[200];
170 sprintf (buf,
171 "process_sigsegv: p=%p stackend=%p diff=%" PRIdPTR "bot=%p\n",
172 p, stackend, diff, stackbot);
173 write (2, buf, strlen (buf));
175 #endif
177 if (p != PARAM_NOSTACKOVF)
179 if ((long) sbrk (8192) == (long) -1)
181 const char *cp;
183 /* sbrk failed. Assume the RLIMIT_VMEM prevents expansion even
184 if the stack limit has not been reached. */
186 /* FIXME - calling gettext inside a signal handler is
187 dangerous, since it can call malloc, which is not signal
188 safe. We can sort of justify it by the fact that this
189 handler is designed to exit() the program, but it could
190 really use a better fix. */
191 cp = _("VMEM limit exceeded?\n");
192 write (2, cp, strlen (cp));
193 p = PARAM_STACKOVF;
195 if (diff >= -STACKOVF_DETECT && diff <= STACKOVF_DETECT)
198 /* The fault address is "sufficiently close" to the stack lim. */
200 p = PARAM_STACKOVF;
202 if (p == PARAM_STACKOVF)
205 /* We have determined that this is indeed a stack overflow. */
207 (*stackovf_handler) (); /* should call exit() */
210 if (p == NULL)
212 const char *cp;
214 /* FIXME - calling gettext inside a signal handler is dangerous,
215 since it can call malloc, which is not signal safe. */
216 cp = _("\
217 Memory bounds violation detected (SIGSEGV). Either a stack overflow\n\
218 occurred, or there is a bug in ");
219 write (2, cp, strlen (cp));
220 write (2, arg0, strlen (arg0));
221 cp = _(". Check for possible infinite recursion.\n");
222 write (2, cp, strlen (cp));
225 /* Return to re-execute the instruction which caused the trap with
226 SIGSEGV set to SIG_DFL. An abort with core dump should occur. */
228 signal (signo, SIG_DFL);
231 #if HAVE_STRUCT_SIGACTION_SA_SIGACTION
233 /* POSIX. */
235 static void
236 sigsegv_handler (int signo, siginfo_t *ip, void *context)
238 process_sigsegv
239 (signo, (ip != NULL
240 && ip->si_signo == SIGSEGV ? (char *) ip->si_addr : NULL));
243 #elif HAVE_SIGINFO_T
245 /* SVR4. */
247 static void
248 sigsegv_handler (int signo, siginfo_t *ip)
250 process_sigsegv
251 (signo, (ip != NULL
252 && ip->si_signo == SIGSEGV ? (char *) ip->si_addr : NULL));
255 #elif HAVE_SIGCONTEXT
257 /* SunOS 4.x (and BSD?). (not tested) */
259 static void
260 sigsegv_handler (int signo, int code, struct sigcontext *scp, char *addr)
262 process_sigsegv (signo, addr);
265 #else /* not HAVE_SIGCONTEXT */
267 /* OS provides no information. */
269 static void
270 sigsegv_handler (int signo)
272 process_sigsegv (signo, NULL);
275 #endif /* not HAVE_SIGCONTEXT */
277 /* Arrange to trap a stack-overflow and call a specified handler. The
278 call is on a dedicated signal stack.
280 argv and envp are as passed to main.
282 If a stack overflow is not detected, then the SIGSEGV is re-raised
283 with action set to SIG_DFL, causing an abort and coredump in the usual
284 way.
286 Detection of a stack overflow depends on the trap address being near
287 the stack limit address. The stack limit cannot be directly
288 determined in a portable way, but we make an estimate based on the
289 address of the argv and environment vectors, their contents, and the
290 maximum stack size obtained using getrlimit. */
292 void
293 setup_stackovf_trap (char *const *argv, char *const *envp, handler_t handler)
295 struct rlimit rl;
296 rlim_t stack_len;
297 int grows_upward;
298 register char *const *v;
299 register char *p;
300 #if HAVE_SIGACTION && defined SA_ONSTACK
301 struct sigaction act;
302 #elif HAVE_SIGVEC && defined SV_ONSTACK
303 struct sigvec vec;
304 #else
306 Error - Do not know how to set up stack-ovf trap handler...
308 #endif
310 arg0 = argv[0];
311 stackovf_handler = handler;
313 /* Calculate the approximate expected addr for a stack-ovf trap. */
315 if (getrlimit (RLIMIT_STACK, &rl) < 0)
316 error (EXIT_FAILURE, errno, _("getrlimit"));
317 stack_len = (rl.rlim_cur < rl.rlim_max ? rl.rlim_cur : rl.rlim_max);
318 stackbot = (char *) argv;
319 grows_upward = ((char *) &stack_len > stackbot);
320 if (grows_upward)
323 /* Grows toward increasing addresses. */
325 for (v = argv; (p = (char *) *v) != NULL; v++)
327 if (p < stackbot)
328 stackbot = p;
330 if ((char *) envp < stackbot)
331 stackbot = (char *) envp;
332 for (v = envp; (p = (char *) *v) != NULL; v++)
334 if (p < stackbot)
335 stackbot = p;
337 stackend = stackbot + stack_len;
339 else
342 /* The stack grows "downward" (toward decreasing addresses). */
344 for (v = argv; (p = (char *) *v) != NULL; v++)
346 if (p > stackbot)
347 stackbot = p;
349 if ((char *) envp > stackbot)
350 stackbot = (char *) envp;
351 for (v = envp; (p = (char *) *v) != NULL; v++)
353 if (p > stackbot)
354 stackbot = p;
356 stackend = stackbot - stack_len;
359 /* Allocate a separate signal-handler stack. */
361 #if HAVE_SIGALTSTACK && (HAVE_SIGINFO_T || ! HAVE_SIGSTACK)
363 /* Use sigaltstack only if siginfo_t is available, unless there is no
364 choice. */
367 stack_t ss;
368 # ifndef HAVE_STACK_T_SS_SP
369 /* This workaround is for BSD/OS 4.0.1:
370 http://lists.gnu.org/archive/html/bug-m4/2006-12/msg00004.html */
371 # define ss_sp ss_base
372 # endif /* ! HAVE_STACK_T_SS_SP */
374 stackbuf = xmalloc (SIGSTKSZ);
376 ss.ss_size = SIGSTKSZ;
377 ss.ss_sp = stackbuf;
378 ss.ss_flags = 0;
379 if (sigaltstack (&ss, NULL) < 0)
381 /* Oops - sigstack exists but doesn't work. We can't install
382 the overflow detector, but should gracefully treat it as
383 though sigstack doesn't exist. For example, this happens
384 when compiled with Linux 2.1 headers but run against Linux
385 2.0 kernel. */
386 free (stackbuf);
387 if (errno == ENOSYS)
388 return;
389 error (EXIT_FAILURE, errno, _("sigaltstack"));
393 #elif HAVE_SIGSTACK
396 struct sigstack ss;
397 stackbuf = xmalloc (2 * SIGSTKSZ);
399 ss.ss_sp = stackbuf + SIGSTKSZ;
400 ss.ss_onstack = 0;
401 if (sigstack (&ss, NULL) < 0)
403 /* Oops - sigstack exists but doesn't work. We can't install
404 the overflow detector, but should gracefully treat it as
405 though sigstack doesn't exist. For example, this happens
406 when compiled with Linux 2.1 headers but run against Linux
407 2.0 kernel. */
408 free (stackbuf);
409 if (errno == ENOSYS)
410 return;
411 error (EXIT_FAILURE, errno, _("sigstack"));
415 #else /* not HAVE_SIGSTACK */
417 Error - Do not know how to set up stack-ovf trap handler...
419 #endif /* not HAVE_SIGSTACK */
421 /* Arm the SIGSEGV signal handler. */
423 #if HAVE_SIGACTION && defined SA_ONSTACK
425 sigaction (SIGSEGV, NULL, &act);
426 # if HAVE_STRUCT_SIGACTION_SA_SIGACTION
427 act.sa_sigaction = sigsegv_handler;
428 # else /* ! HAVE_STRUCT_SIGACTION_SA_SIGACTION */
429 act.sa_handler = (RETSIGTYPE (*) (int)) sigsegv_handler;
430 # endif /* ! HAVE_STRUCT_SIGACTION_SA_SIGACTION */
431 sigemptyset (&act.sa_mask);
432 act.sa_flags = (SA_ONSTACK | SA_RESETHAND | SA_SIGINFO);
433 if (sigaction (SIGSEGV, &act, NULL) < 0)
434 error (EXIT_FAILURE, errno, _("sigaction"));
436 #else /* ! HAVE_SIGACTION */
438 vec.sv_handler = (RETSIGTYPE (*) (int)) sigsegv_handler;
439 vec.sv_mask = 0;
440 vec.sv_flags = (SV_ONSTACK | SV_RESETHAND);
441 if (sigvec (SIGSEGV, &vec, NULL) < 0)
442 error (EXIT_FAILURE, errno, _("sigvec"));
444 #endif /* ! HAVE_SIGACTION */
448 void
449 stackovf_exit (void)
451 DELETE (stackbuf);
454 #endif /* USE_STACKOVF */