1/* Stack overflow handling.
2
3   Copyright (C) 2002, 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 Foundation,
17   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
18
19/* Written by Paul Eggert.  */
20
21/* NOTES:
22
23   A program that uses alloca, dynamic arrays, or large local
24   variables may extend the stack by more than a page at a time.  If
25   so, when the stack overflows the operating system may not detect
26   the overflow until the program uses the array, and this module may
27   incorrectly report a program error instead of a stack overflow.
28
29   To avoid this problem, allocate only small objects on the stack; a
30   program should be OK if it limits single allocations to a page or
31   less.  Allocate larger arrays in static storage, or on the heap
32   (e.g., with malloc).  Yes, this is a pain, but we don't know of any
33   better solution that is portable.
34
35   No attempt has been made to deal with multithreaded applications.  */
36
37#if HAVE_CONFIG_H
38# include <config.h>
39#endif
40
41#ifndef __attribute__
42# if __GNUC__ < 3 || __STRICT_ANSI__
43#  define __attribute__(x)
44# endif
45#endif
46
47#include "gettext.h"
48#define _(msgid) gettext (msgid)
49
50#include <errno.h>
51#ifndef ENOTSUP
52# define ENOTSUP EINVAL
53#endif
54#ifndef EOVERFLOW
55# define EOVERFLOW EINVAL
56#endif
57
58#include <signal.h>
59#if ! HAVE_STACK_T && ! defined stack_t
60typedef struct sigaltstack stack_t;
61#endif
62
63#include <stdlib.h>
64#include <string.h>
65
66#if HAVE_SYS_RESOURCE_H
67/* Include sys/time.h here, because...
68   SunOS-4.1.x <sys/resource.h> fails to include <sys/time.h>.
69   This gives "incomplete type" errors for ru_utime and tu_stime.  */
70# if HAVE_SYS_TIME_H
71#  include <sys/time.h>
72# endif
73# include <sys/resource.h>
74#endif
75
76#if HAVE_UCONTEXT_H
77# include <ucontext.h>
78#endif
79
80#if HAVE_UNISTD_H
81# include <unistd.h>
82#endif
83#ifndef STDERR_FILENO
84# define STDERR_FILENO 2
85#endif
86
87#if DEBUG
88# include <stdio.h>
89#endif
90
91#include "c-stack.h"
92#include "exitfail.h"
93
94#if (HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined SA_NODEFER \
95     && defined SA_ONSTACK && defined SA_RESETHAND && defined SA_SIGINFO)
96# define SIGACTION_WORKS 1
97#else
98# define SIGACTION_WORKS 0
99#endif
100
101extern char *program_name;
102
103/* The user-specified action to take when a SEGV-related program error
104   or stack overflow occurs.  */
105static void (* volatile segv_action) (int);
106
107/* Translated messages for program errors and stack overflow.  Do not
108   translate them in the signal handler, since gettext is not
109   async-signal-safe.  */
110static char const * volatile program_error_message;
111static char const * volatile stack_overflow_message;
112
113/* Output an error message, then exit with status EXIT_FAILURE if it
114   appears to have been a stack overflow, or with a core dump
115   otherwise.  This function is async-signal-safe.  */
116
117static void die (int) __attribute__ ((noreturn));
118static void
119die (int signo)
120{
121  char const *message;
122  segv_action (signo);
123  message = signo ? program_error_message : stack_overflow_message;
124  write (STDERR_FILENO, program_name, strlen (program_name));
125  write (STDERR_FILENO, ": ", 2);
126  write (STDERR_FILENO, message, strlen (message));
127  write (STDERR_FILENO, "\n", 1);
128  if (! signo)
129    _exit (exit_failure);
130  kill (getpid (), signo);
131  abort ();
132}
133
134#if HAVE_SIGALTSTACK && HAVE_DECL_SIGALTSTACK
135
136/* Direction of the C runtime stack.  This function is
137   async-signal-safe.  */
138
139# if STACK_DIRECTION
140#  define find_stack_direction(ptr) STACK_DIRECTION
141# else
142static int
143find_stack_direction (char const *addr)
144{
145  char dummy;
146  return ! addr ? find_stack_direction (&dummy) : addr < &dummy ? 1 : -1;
147}
148# endif
149
150/* Storage for the alternate signal stack.  */
151static union
152{
153  char buffer[SIGSTKSZ];
154
155  /* These other members are for proper alignment.  There's no
156     standard way to guarantee stack alignment, but this seems enough
157     in practice.  */
158  long double ld;
159  long l;
160  void *p;
161} alternate_signal_stack;
162
163# if SIGACTION_WORKS
164
165/* Handle a segmentation violation and exit.  This function is
166   async-signal-safe.  */
167
168static void segv_handler (int, siginfo_t *, void *) __attribute__((noreturn));
169static void
170segv_handler (int signo, siginfo_t *info,
171	      void *context __attribute__ ((unused)))
172{
173  /* Clear SIGNO if it seems to have been a stack overflow.  */
174  if (0 < info->si_code)
175    {
176#  if ! HAVE_XSI_STACK_OVERFLOW_HEURISTIC
177      /* We can't easily determine whether it is a stack overflow; so
178	 assume that the rest of our program is perfect (!) and that
179	 this segmentation violation is a stack overflow.  */
180      signo = 0;
181#  else
182      /* If the faulting address is within the stack, or within one
183	 page of the stack end, assume that it is a stack
184	 overflow.  */
185      ucontext_t const *user_context = context;
186      char const *stack_base = user_context->uc_stack.ss_sp;
187      size_t stack_size = user_context->uc_stack.ss_size;
188      char const *faulting_address = info->si_addr;
189      size_t s = faulting_address - stack_base;
190      size_t page_size = sysconf (_SC_PAGESIZE);
191      if (find_stack_direction (0) < 0)
192	s += page_size;
193      if (s < stack_size + page_size)
194	signo = 0;
195
196#   if DEBUG
197      {
198	char buf[1024];
199	sprintf (buf,
200		 "segv_handler fault=%p base=%p size=%lx page=%lx signo=%d\n",
201		 faulting_address, stack_base, (unsigned long) stack_size,
202		 (unsigned long) page_size, signo);
203	write (STDERR_FILENO, buf, strlen (buf));
204      }
205#   endif
206#  endif
207    }
208
209  die (signo);
210}
211# endif
212
213static void
214null_action (int signo __attribute__ ((unused)))
215{
216}
217
218/* Set up ACTION so that it is invoked on C stack overflow.  Return -1
219   (setting errno) if this cannot be done.
220
221   When ACTION is called, it is passed an argument equal to SIGSEGV
222   for a segmentation violation that does not appear related to stack
223   overflow, and is passed zero otherwise.  On many platforms it is
224   hard to tell; when in doubt, zero is passed.
225
226   A null ACTION acts like an action that does nothing.
227
228   ACTION must be async-signal-safe.  ACTION together with its callees
229   must not require more than SIGSTKSZ bytes of stack space.  */
230
231int
232c_stack_action (void (*action) (int))
233{
234  int r;
235  stack_t st;
236  st.ss_flags = 0;
237  st.ss_sp = alternate_signal_stack.buffer;
238  st.ss_size = sizeof alternate_signal_stack.buffer;
239  r = sigaltstack (&st, 0);
240  if (r != 0)
241    return r;
242
243  segv_action = action ? action : null_action;
244  program_error_message = _("program error");
245  stack_overflow_message = _("stack overflow");
246
247  {
248# if SIGACTION_WORKS
249    struct sigaction act;
250    sigemptyset (&act.sa_mask);
251
252    /* POSIX 1003.1-2001 says SA_RESETHAND implies SA_NODEFER, but
253       this is not true on Solaris 8 at least.  It doesn't hurt to use
254       SA_NODEFER here, so leave it in.  */
255    act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
256
257    act.sa_sigaction = segv_handler;
258
259    return sigaction (SIGSEGV, &act, 0);
260# else
261    return signal (SIGSEGV, die) == SIG_ERR ? -1 : 0;
262# endif
263  }
264}
265
266#else /* ! (HAVE_SIGALTSTACK && HAVE_DECL_SIGALTSTACK) */
267
268int
269c_stack_action (void (*action) (int)  __attribute__ ((unused)))
270{
271  errno = ENOTSUP;
272  return -1;
273}
274
275#endif
276
277
278
279#if DEBUG
280
281int volatile exit_failure;
282
283static long
284recurse (char *p)
285{
286  char array[500];
287  array[0] = 1;
288  return *p + recurse (array);
289}
290
291char *program_name;
292
293int
294main (int argc __attribute__ ((unused)), char **argv)
295{
296  program_name = argv[0];
297  fprintf (stderr,
298	   "The last output line should contain \"stack overflow\".\n");
299  if (c_stack_action (0) == 0)
300    return recurse ("\1");
301  perror ("c_stack_action");
302  return 1;
303}
304
305#endif /* DEBUG */
306
307/*
308Local Variables:
309compile-command: "gcc -DDEBUG -DHAVE_CONFIG_H -I.. -g -O -Wall -W c-stack.c"
310End:
311*/
312