/* Stack overflow handling.12Copyright (C) 2002, 2004 Free Software Foundation, Inc.34This program is free software; you can redistribute it and/or modify5it under the terms of the GNU General Public License as published by6the Free Software Foundation; either version 2, or (at your option)7any later version.89This program is distributed in the hope that it will be useful,10but WITHOUT ANY WARRANTY; without even the implied warranty of11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12GNU General Public License for more details.1314You should have received a copy of the GNU General Public License15along with this program; if not, write to the Free Software Foundation,16Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */1718/* Written by Paul Eggert. */1920/* NOTES:2122A program that uses alloca, dynamic arrays, or large local23variables may extend the stack by more than a page at a time. If24so, when the stack overflows the operating system may not detect25the overflow until the program uses the array, and this module may26incorrectly report a program error instead of a stack overflow.2728To avoid this problem, allocate only small objects on the stack; a29program should be OK if it limits single allocations to a page or30less. Allocate larger arrays in static storage, or on the heap31(e.g., with malloc). Yes, this is a pain, but we don't know of any32better solution that is portable.3334No attempt has been made to deal with multithreaded applications. */3536#if HAVE_CONFIG_H37# include <config.h>38#endif3940#ifndef __attribute__41# if __GNUC__ < 3 || __STRICT_ANSI__42# define __attribute__(x)43# endif44#endif4546#include "gettext.h"47#define _(msgid) gettext (msgid)4849#include <errno.h>50#ifndef ENOTSUP51# define ENOTSUP EINVAL52#endif53#ifndef EOVERFLOW54# define EOVERFLOW EINVAL55#endif5657#include <signal.h>58#if ! HAVE_STACK_T && ! defined stack_t59typedef struct sigaltstack stack_t;60#endif6162#include <stdlib.h>63#include <string.h>6465#if HAVE_SYS_RESOURCE_H66/* Include sys/time.h here, because...67SunOS-4.1.x <sys/resource.h> fails to include <sys/time.h>.68This gives "incomplete type" errors for ru_utime and tu_stime. */69# if HAVE_SYS_TIME_H70# include <sys/time.h>71# endif72# include <sys/resource.h>73#endif7475#if HAVE_UCONTEXT_H76# include <ucontext.h>77#endif7879#if HAVE_UNISTD_H80# include <unistd.h>81#endif82#ifndef STDERR_FILENO83# define STDERR_FILENO 284#endif8586#if DEBUG87# include <stdio.h>88#endif8990#include "c-stack.h"91#include "exitfail.h"9293#if (HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined SA_NODEFER \94&& defined SA_ONSTACK && defined SA_RESETHAND && defined SA_SIGINFO)95# define SIGACTION_WORKS 196#else97# define SIGACTION_WORKS 098#endif99100extern char *program_name;101102/* The user-specified action to take when a SEGV-related program error103or stack overflow occurs. */104static void (* volatile segv_action) (int);105106/* Translated messages for program errors and stack overflow. Do not107translate them in the signal handler, since gettext is not108async-signal-safe. */109static char const * volatile program_error_message;110static char const * volatile stack_overflow_message;111112/* Output an error message, then exit with status EXIT_FAILURE if it113appears to have been a stack overflow, or with a core dump114otherwise. This function is async-signal-safe. */115116static void die (int) __attribute__ ((noreturn));117static void118die (int signo)119{120char const *message;121segv_action (signo);122message = signo ? program_error_message : stack_overflow_message;123write (STDERR_FILENO, program_name, strlen (program_name));124write (STDERR_FILENO, ": ", 2);125write (STDERR_FILENO, message, strlen (message));126write (STDERR_FILENO, "\n", 1);127if (! signo)128_exit (exit_failure);129kill (getpid (), signo);130abort ();131}132133#if HAVE_SIGALTSTACK && HAVE_DECL_SIGALTSTACK134135/* Direction of the C runtime stack. This function is136async-signal-safe. */137138# if STACK_DIRECTION139# define find_stack_direction(ptr) STACK_DIRECTION140# else141static int142find_stack_direction (char const *addr)143{144char dummy;145return ! addr ? find_stack_direction (&dummy) : addr < &dummy ? 1 : -1;146}147# endif148149/* Storage for the alternate signal stack. */150static union151{152char buffer[SIGSTKSZ];153154/* These other members are for proper alignment. There's no155standard way to guarantee stack alignment, but this seems enough156in practice. */157long double ld;158long l;159void *p;160} alternate_signal_stack;161162# if SIGACTION_WORKS163164/* Handle a segmentation violation and exit. This function is165async-signal-safe. */166167static void segv_handler (int, siginfo_t *, void *) __attribute__((noreturn));168static void169segv_handler (int signo, siginfo_t *info,170void *context __attribute__ ((unused)))171{172/* Clear SIGNO if it seems to have been a stack overflow. */173if (0 < info->si_code)174{175# if ! HAVE_XSI_STACK_OVERFLOW_HEURISTIC176/* We can't easily determine whether it is a stack overflow; so177assume that the rest of our program is perfect (!) and that178this segmentation violation is a stack overflow. */179signo = 0;180# else181/* If the faulting address is within the stack, or within one182page of the stack end, assume that it is a stack183overflow. */184ucontext_t const *user_context = context;185char const *stack_base = user_context->uc_stack.ss_sp;186size_t stack_size = user_context->uc_stack.ss_size;187char const *faulting_address = info->si_addr;188size_t s = faulting_address - stack_base;189size_t page_size = sysconf (_SC_PAGESIZE);190if (find_stack_direction (0) < 0)191s += page_size;192if (s < stack_size + page_size)193signo = 0;194195# if DEBUG196{197char buf[1024];198sprintf (buf,199"segv_handler fault=%p base=%p size=%lx page=%lx signo=%d\n",200faulting_address, stack_base, (unsigned long) stack_size,201(unsigned long) page_size, signo);202write (STDERR_FILENO, buf, strlen (buf));203}204# endif205# endif206}207208die (signo);209}210# endif211212static void213null_action (int signo __attribute__ ((unused)))214{215}216217/* Set up ACTION so that it is invoked on C stack overflow. Return -1218(setting errno) if this cannot be done.219220When ACTION is called, it is passed an argument equal to SIGSEGV221for a segmentation violation that does not appear related to stack222overflow, and is passed zero otherwise. On many platforms it is223hard to tell; when in doubt, zero is passed.224225A null ACTION acts like an action that does nothing.226227ACTION must be async-signal-safe. ACTION together with its callees228must not require more than SIGSTKSZ bytes of stack space. */229230int231c_stack_action (void (*action) (int))232{233int r;234stack_t st;235st.ss_flags = 0;236st.ss_sp = alternate_signal_stack.buffer;237st.ss_size = sizeof alternate_signal_stack.buffer;238r = sigaltstack (&st, 0);239if (r != 0)240return r;241242segv_action = action ? action : null_action;243program_error_message = _("program error");244stack_overflow_message = _("stack overflow");245246{247# if SIGACTION_WORKS248struct sigaction act;249sigemptyset (&act.sa_mask);250251/* POSIX 1003.1-2001 says SA_RESETHAND implies SA_NODEFER, but252this is not true on Solaris 8 at least. It doesn't hurt to use253SA_NODEFER here, so leave it in. */254act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;255256act.sa_sigaction = segv_handler;257258return sigaction (SIGSEGV, &act, 0);259# else260return signal (SIGSEGV, die) == SIG_ERR ? -1 : 0;261# endif262}263}264265#else /* ! (HAVE_SIGALTSTACK && HAVE_DECL_SIGALTSTACK) */266267int268c_stack_action (void (*action) (int) __attribute__ ((unused)))269{270errno = ENOTSUP;271return -1;272}273274#endif275276277278#if DEBUG279280int volatile exit_failure;281282static long283recurse (char *p)284{285char array[500];286array[0] = 1;287return *p + recurse (array);288}289290char *program_name;291292int293main (int argc __attribute__ ((unused)), char **argv)294{295program_name = argv[0];296fprintf (stderr,297"The last output line should contain \"stack overflow\".\n");298if (c_stack_action (0) == 0)299return recurse ("\1");300perror ("c_stack_action");301return 1;302}303304#endif /* DEBUG */305306/*307Local Variables:308compile-command: "gcc -DDEBUG -DHAVE_CONFIG_H -I.. -g -O -Wall -W c-stack.c"309End:310*/311312313