1170754Sdelphij/* Stack overflow handling.
2170754Sdelphij
3170754Sdelphij   Copyright (C) 2002, 2004 Free Software Foundation, Inc.
4170754Sdelphij
5170754Sdelphij   This program is free software; you can redistribute it and/or modify
6170754Sdelphij   it under the terms of the GNU General Public License as published by
7170754Sdelphij   the Free Software Foundation; either version 2, or (at your option)
8170754Sdelphij   any later version.
9170754Sdelphij
10170754Sdelphij   This program is distributed in the hope that it will be useful,
11170754Sdelphij   but WITHOUT ANY WARRANTY; without even the implied warranty of
12170754Sdelphij   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13170754Sdelphij   GNU General Public License for more details.
14170754Sdelphij
15170754Sdelphij   You should have received a copy of the GNU General Public License
16170754Sdelphij   along with this program; if not, write to the Free Software Foundation,
17170754Sdelphij   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
18170754Sdelphij
19170754Sdelphij/* Written by Paul Eggert.  */
20170754Sdelphij
21170754Sdelphij/* NOTES:
22170754Sdelphij
23170754Sdelphij   A program that uses alloca, dynamic arrays, or large local
24170754Sdelphij   variables may extend the stack by more than a page at a time.  If
25170754Sdelphij   so, when the stack overflows the operating system may not detect
26170754Sdelphij   the overflow until the program uses the array, and this module may
27170754Sdelphij   incorrectly report a program error instead of a stack overflow.
28170754Sdelphij
29170754Sdelphij   To avoid this problem, allocate only small objects on the stack; a
30170754Sdelphij   program should be OK if it limits single allocations to a page or
31170754Sdelphij   less.  Allocate larger arrays in static storage, or on the heap
32170754Sdelphij   (e.g., with malloc).  Yes, this is a pain, but we don't know of any
33170754Sdelphij   better solution that is portable.
34170754Sdelphij
35170754Sdelphij   No attempt has been made to deal with multithreaded applications.  */
36170754Sdelphij
37170754Sdelphij#if HAVE_CONFIG_H
38170754Sdelphij# include <config.h>
39170754Sdelphij#endif
40170754Sdelphij
41170754Sdelphij#ifndef __attribute__
42170754Sdelphij# if __GNUC__ < 3 || __STRICT_ANSI__
43170754Sdelphij#  define __attribute__(x)
44170754Sdelphij# endif
45170754Sdelphij#endif
46170754Sdelphij
47170754Sdelphij#include "gettext.h"
48170754Sdelphij#define _(msgid) gettext (msgid)
49170754Sdelphij
50170754Sdelphij#include <errno.h>
51170754Sdelphij#ifndef ENOTSUP
52170754Sdelphij# define ENOTSUP EINVAL
53170754Sdelphij#endif
54170754Sdelphij#ifndef EOVERFLOW
55170754Sdelphij# define EOVERFLOW EINVAL
56170754Sdelphij#endif
57170754Sdelphij
58170754Sdelphij#include <signal.h>
59170754Sdelphij#if ! HAVE_STACK_T && ! defined stack_t
60170754Sdelphijtypedef struct sigaltstack stack_t;
61170754Sdelphij#endif
62170754Sdelphij
63170754Sdelphij#include <stdlib.h>
64170754Sdelphij#include <string.h>
65170754Sdelphij
66170754Sdelphij#if HAVE_SYS_RESOURCE_H
67170754Sdelphij/* Include sys/time.h here, because...
68170754Sdelphij   SunOS-4.1.x <sys/resource.h> fails to include <sys/time.h>.
69170754Sdelphij   This gives "incomplete type" errors for ru_utime and tu_stime.  */
70170754Sdelphij# if HAVE_SYS_TIME_H
71170754Sdelphij#  include <sys/time.h>
72170754Sdelphij# endif
73170754Sdelphij# include <sys/resource.h>
74170754Sdelphij#endif
75170754Sdelphij
76170754Sdelphij#if HAVE_UCONTEXT_H
77170754Sdelphij# include <ucontext.h>
78170754Sdelphij#endif
79170754Sdelphij
80170754Sdelphij#if HAVE_UNISTD_H
81170754Sdelphij# include <unistd.h>
82170754Sdelphij#endif
83170754Sdelphij#ifndef STDERR_FILENO
84170754Sdelphij# define STDERR_FILENO 2
85170754Sdelphij#endif
86170754Sdelphij
87170754Sdelphij#if DEBUG
88170754Sdelphij# include <stdio.h>
89170754Sdelphij#endif
90170754Sdelphij
91170754Sdelphij#include "c-stack.h"
92170754Sdelphij#include "exitfail.h"
93170754Sdelphij
94170754Sdelphij#if (HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined SA_NODEFER \
95170754Sdelphij     && defined SA_ONSTACK && defined SA_RESETHAND && defined SA_SIGINFO)
96170754Sdelphij# define SIGACTION_WORKS 1
97170754Sdelphij#else
98170754Sdelphij# define SIGACTION_WORKS 0
99170754Sdelphij#endif
100170754Sdelphij
101170754Sdelphijextern char *program_name;
102170754Sdelphij
103170754Sdelphij/* The user-specified action to take when a SEGV-related program error
104170754Sdelphij   or stack overflow occurs.  */
105170754Sdelphijstatic void (* volatile segv_action) (int);
106170754Sdelphij
107170754Sdelphij/* Translated messages for program errors and stack overflow.  Do not
108170754Sdelphij   translate them in the signal handler, since gettext is not
109170754Sdelphij   async-signal-safe.  */
110170754Sdelphijstatic char const * volatile program_error_message;
111170754Sdelphijstatic char const * volatile stack_overflow_message;
112170754Sdelphij
113170754Sdelphij/* Output an error message, then exit with status EXIT_FAILURE if it
114170754Sdelphij   appears to have been a stack overflow, or with a core dump
115170754Sdelphij   otherwise.  This function is async-signal-safe.  */
116170754Sdelphij
117170754Sdelphijstatic void die (int) __attribute__ ((noreturn));
118170754Sdelphijstatic void
119170754Sdelphijdie (int signo)
120170754Sdelphij{
121170754Sdelphij  char const *message;
122170754Sdelphij  segv_action (signo);
123170754Sdelphij  message = signo ? program_error_message : stack_overflow_message;
124170754Sdelphij  write (STDERR_FILENO, program_name, strlen (program_name));
125170754Sdelphij  write (STDERR_FILENO, ": ", 2);
126170754Sdelphij  write (STDERR_FILENO, message, strlen (message));
127170754Sdelphij  write (STDERR_FILENO, "\n", 1);
128170754Sdelphij  if (! signo)
129170754Sdelphij    _exit (exit_failure);
130170754Sdelphij  kill (getpid (), signo);
131170754Sdelphij  abort ();
132170754Sdelphij}
133170754Sdelphij
134170754Sdelphij#if HAVE_SIGALTSTACK && HAVE_DECL_SIGALTSTACK
135170754Sdelphij
136170754Sdelphij/* Direction of the C runtime stack.  This function is
137170754Sdelphij   async-signal-safe.  */
138170754Sdelphij
139170754Sdelphij# if STACK_DIRECTION
140170754Sdelphij#  define find_stack_direction(ptr) STACK_DIRECTION
141170754Sdelphij# else
142170754Sdelphijstatic int
143170754Sdelphijfind_stack_direction (char const *addr)
144170754Sdelphij{
145170754Sdelphij  char dummy;
146170754Sdelphij  return ! addr ? find_stack_direction (&dummy) : addr < &dummy ? 1 : -1;
147170754Sdelphij}
148170754Sdelphij# endif
149170754Sdelphij
150170754Sdelphij/* Storage for the alternate signal stack.  */
151170754Sdelphijstatic union
152170754Sdelphij{
153170754Sdelphij  char buffer[SIGSTKSZ];
154170754Sdelphij
155170754Sdelphij  /* These other members are for proper alignment.  There's no
156170754Sdelphij     standard way to guarantee stack alignment, but this seems enough
157170754Sdelphij     in practice.  */
158170754Sdelphij  long double ld;
159170754Sdelphij  long l;
160170754Sdelphij  void *p;
161170754Sdelphij} alternate_signal_stack;
162170754Sdelphij
163170754Sdelphij# if SIGACTION_WORKS
164170754Sdelphij
165170754Sdelphij/* Handle a segmentation violation and exit.  This function is
166170754Sdelphij   async-signal-safe.  */
167170754Sdelphij
168170754Sdelphijstatic void segv_handler (int, siginfo_t *, void *) __attribute__((noreturn));
169170754Sdelphijstatic void
170170754Sdelphijsegv_handler (int signo, siginfo_t *info,
171170754Sdelphij	      void *context __attribute__ ((unused)))
172170754Sdelphij{
173170754Sdelphij  /* Clear SIGNO if it seems to have been a stack overflow.  */
174170754Sdelphij  if (0 < info->si_code)
175170754Sdelphij    {
176170754Sdelphij#  if ! HAVE_XSI_STACK_OVERFLOW_HEURISTIC
177170754Sdelphij      /* We can't easily determine whether it is a stack overflow; so
178170754Sdelphij	 assume that the rest of our program is perfect (!) and that
179170754Sdelphij	 this segmentation violation is a stack overflow.  */
180170754Sdelphij      signo = 0;
181170754Sdelphij#  else
182170754Sdelphij      /* If the faulting address is within the stack, or within one
183170754Sdelphij	 page of the stack end, assume that it is a stack
184170754Sdelphij	 overflow.  */
185170754Sdelphij      ucontext_t const *user_context = context;
186170754Sdelphij      char const *stack_base = user_context->uc_stack.ss_sp;
187170754Sdelphij      size_t stack_size = user_context->uc_stack.ss_size;
188170754Sdelphij      char const *faulting_address = info->si_addr;
189170754Sdelphij      size_t s = faulting_address - stack_base;
190170754Sdelphij      size_t page_size = sysconf (_SC_PAGESIZE);
191170754Sdelphij      if (find_stack_direction (0) < 0)
192170754Sdelphij	s += page_size;
193170754Sdelphij      if (s < stack_size + page_size)
194170754Sdelphij	signo = 0;
195170754Sdelphij
196170754Sdelphij#   if DEBUG
197170754Sdelphij      {
198170754Sdelphij	char buf[1024];
199170754Sdelphij	sprintf (buf,
200170754Sdelphij		 "segv_handler fault=%p base=%p size=%lx page=%lx signo=%d\n",
201170754Sdelphij		 faulting_address, stack_base, (unsigned long) stack_size,
202170754Sdelphij		 (unsigned long) page_size, signo);
203170754Sdelphij	write (STDERR_FILENO, buf, strlen (buf));
204170754Sdelphij      }
205170754Sdelphij#   endif
206170754Sdelphij#  endif
207170754Sdelphij    }
208170754Sdelphij
209170754Sdelphij  die (signo);
210170754Sdelphij}
211170754Sdelphij# endif
212170754Sdelphij
213170754Sdelphijstatic void
214170754Sdelphijnull_action (int signo __attribute__ ((unused)))
215170754Sdelphij{
216170754Sdelphij}
217170754Sdelphij
218170754Sdelphij/* Set up ACTION so that it is invoked on C stack overflow.  Return -1
219170754Sdelphij   (setting errno) if this cannot be done.
220170754Sdelphij
221170754Sdelphij   When ACTION is called, it is passed an argument equal to SIGSEGV
222170754Sdelphij   for a segmentation violation that does not appear related to stack
223170754Sdelphij   overflow, and is passed zero otherwise.  On many platforms it is
224170754Sdelphij   hard to tell; when in doubt, zero is passed.
225170754Sdelphij
226170754Sdelphij   A null ACTION acts like an action that does nothing.
227170754Sdelphij
228170754Sdelphij   ACTION must be async-signal-safe.  ACTION together with its callees
229170754Sdelphij   must not require more than SIGSTKSZ bytes of stack space.  */
230170754Sdelphij
231170754Sdelphijint
232170754Sdelphijc_stack_action (void (*action) (int))
233170754Sdelphij{
234170754Sdelphij  int r;
235170754Sdelphij  stack_t st;
236170754Sdelphij  st.ss_flags = 0;
237170754Sdelphij  st.ss_sp = alternate_signal_stack.buffer;
238170754Sdelphij  st.ss_size = sizeof alternate_signal_stack.buffer;
239170754Sdelphij  r = sigaltstack (&st, 0);
240170754Sdelphij  if (r != 0)
241170754Sdelphij    return r;
242170754Sdelphij
243170754Sdelphij  segv_action = action ? action : null_action;
244170754Sdelphij  program_error_message = _("program error");
245170754Sdelphij  stack_overflow_message = _("stack overflow");
246170754Sdelphij
247170754Sdelphij  {
248170754Sdelphij# if SIGACTION_WORKS
249170754Sdelphij    struct sigaction act;
250170754Sdelphij    sigemptyset (&act.sa_mask);
251170754Sdelphij
252170754Sdelphij    /* POSIX 1003.1-2001 says SA_RESETHAND implies SA_NODEFER, but
253170754Sdelphij       this is not true on Solaris 8 at least.  It doesn't hurt to use
254170754Sdelphij       SA_NODEFER here, so leave it in.  */
255170754Sdelphij    act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
256170754Sdelphij
257170754Sdelphij    act.sa_sigaction = segv_handler;
258170754Sdelphij
259170754Sdelphij    return sigaction (SIGSEGV, &act, 0);
260170754Sdelphij# else
261170754Sdelphij    return signal (SIGSEGV, die) == SIG_ERR ? -1 : 0;
262170754Sdelphij# endif
263170754Sdelphij  }
264170754Sdelphij}
265170754Sdelphij
266170754Sdelphij#else /* ! (HAVE_SIGALTSTACK && HAVE_DECL_SIGALTSTACK) */
267170754Sdelphij
268170754Sdelphijint
269170754Sdelphijc_stack_action (void (*action) (int)  __attribute__ ((unused)))
270170754Sdelphij{
271170754Sdelphij  errno = ENOTSUP;
272170754Sdelphij  return -1;
273170754Sdelphij}
274170754Sdelphij
275170754Sdelphij#endif
276170754Sdelphij
277170754Sdelphij
278170754Sdelphij
279170754Sdelphij#if DEBUG
280170754Sdelphij
281170754Sdelphijint volatile exit_failure;
282170754Sdelphij
283170754Sdelphijstatic long
284170754Sdelphijrecurse (char *p)
285170754Sdelphij{
286170754Sdelphij  char array[500];
287170754Sdelphij  array[0] = 1;
288170754Sdelphij  return *p + recurse (array);
289170754Sdelphij}
290170754Sdelphij
291170754Sdelphijchar *program_name;
292170754Sdelphij
293170754Sdelphijint
294170754Sdelphijmain (int argc __attribute__ ((unused)), char **argv)
295170754Sdelphij{
296170754Sdelphij  program_name = argv[0];
297170754Sdelphij  fprintf (stderr,
298170754Sdelphij	   "The last output line should contain \"stack overflow\".\n");
299170754Sdelphij  if (c_stack_action (0) == 0)
300170754Sdelphij    return recurse ("\1");
301170754Sdelphij  perror ("c_stack_action");
302170754Sdelphij  return 1;
303170754Sdelphij}
304170754Sdelphij
305170754Sdelphij#endif /* DEBUG */
306170754Sdelphij
307170754Sdelphij/*
308170754SdelphijLocal Variables:
309170754Sdelphijcompile-command: "gcc -DDEBUG -DHAVE_CONFIG_H -I.. -g -O -Wall -W c-stack.c"
310170754SdelphijEnd:
311170754Sdelphij*/
312