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