1/* Stack overflow handling. 2 3 Copyright (C) 2002 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/* This module assumes that each stack frame is smaller than a page. 22 If you use alloca, dynamic arrays, or large local variables, your 23 program may extend the stack by more than a page at a time. If so, 24 the code below may incorrectly report a program error, or worse 25 yet, may not detect the overflow at all. To avoid this problem, 26 don't use large local arrays. */ 27 28#if HAVE_CONFIG_H 29# include <config.h> 30#endif 31 32#include "gettext.h" 33#define _(msgid) gettext (msgid) 34 35#include <errno.h> 36#ifndef ENOTSUP 37# define ENOTSUP EINVAL 38#endif 39 40#if HAVE_INTTYPES_H 41# include <inttypes.h> 42#else 43# if HAVE_STDINT_H 44# include <stdint.h> 45# endif 46#endif 47 48#include <signal.h> 49#include <stdlib.h> 50#include <string.h> 51 52#if HAVE_UNISTD_H 53# include <unistd.h> 54#endif 55#ifndef STDERR_FILENO 56# define STDERR_FILENO 2 57#endif 58 59#include "c-stack.h" 60#include "exitfail.h" 61 62extern char *program_name; 63 64#if HAVE_XSI_STACK_OVERFLOW_HEURISTIC 65 66# include <ucontext.h> 67 68 69/* Storage for the alternate signal stack. */ 70static union 71{ 72 char buffer[SIGSTKSZ]; 73 74 /* These other members are for proper alignment. There's no 75 standard way to guarantee stack alignment, but this seems enough 76 in practice. */ 77 long double ld; 78 uintmax_t u; 79 void *p; 80} alternate_signal_stack; 81 82 83/* Direction of the C runtime stack. This function is 84 async-signal-safe. */ 85 86# if STACK_DIRECTION 87# define find_stack_direction(ptr) STACK_DIRECTION 88# else 89static int 90find_stack_direction (char const *addr) 91{ 92 char dummy; 93 return ! addr ? find_stack_direction (&dummy) : addr < &dummy ? 1 : -1; 94} 95# endif 96 97/* The SIGSEGV handler. */ 98static void (* volatile segv_action) (int, siginfo_t *, void *); 99 100/* Handle a segmentation violation and exit. This function is 101 async-signal-safe. */ 102 103static void 104segv_handler (int signo, siginfo_t *info, void *context) 105{ 106 /* Clear SIGNO if it seems to have been a stack overflow. */ 107 if (0 < info->si_code) 108 { 109 /* If the faulting address is within the stack, or within one 110 page of the stack end, assume that it is a stack 111 overflow. */ 112 ucontext_t const *user_context = context; 113 char const *stack_min = user_context->uc_stack.ss_sp; 114 size_t stack_size = user_context->uc_stack.ss_size; 115 char const *faulting_address = info->si_addr; 116 size_t s = faulting_address - stack_min; 117 size_t page_size = sysconf (_SC_PAGESIZE); 118 if (find_stack_direction (0) < 0) 119 s += page_size; 120 if (s < stack_size + page_size) 121 signo = 0; 122 } 123 124 segv_action (signo, info, context); 125} 126 127#endif /* HAVE_XSI_STACK_OVERFLOW_HEURISTIC */ 128 129 130/* Translated messages for program errors and stack overflow. Do not 131 translate them in the signal handler, since gettext is not 132 async-signal-safe. */ 133static char const * volatile program_error_message; 134static char const * volatile stack_overflow_message; 135 136/* Output an error message, then exit with status EXIT_FAILURE if it 137 appears to have been a stack overflow, or with a core dump 138 otherwise. This function is async-signal-safe. */ 139 140void 141c_stack_die (int signo, siginfo_t *info, void *context) 142{ 143 char const *message = 144 signo ? program_error_message : stack_overflow_message; 145 write (STDERR_FILENO, program_name, strlen (program_name)); 146 write (STDERR_FILENO, ": ", 2); 147 write (STDERR_FILENO, message, strlen (message)); 148 write (STDERR_FILENO, "\n", 1); 149 if (! signo) 150 _exit (exit_failure); 151#if HAVE_SIGINFO_T 152 if (context && info && 0 <= info->si_code) 153 { 154 /* Re-raise the exception at the same address. */ 155 char *addr = info->si_addr; 156 *addr = 0; 157 } 158#endif 159 kill (getpid (), signo); 160} 161 162 163/* Set up ACTION so that it is invoked on C stack overflow. Return -1 164 (setting errno) if this cannot be done. 165 166 ACTION must invoke only async-signal-safe functions. ACTION 167 together with its callees must not require more than SIGSTKSZ bytes 168 of stack space. */ 169 170int 171c_stack_action (void (*action) (int, siginfo_t *, void *)) 172{ 173#if ! HAVE_XSI_STACK_OVERFLOW_HEURISTIC 174 errno = ENOTSUP; 175 return -1; 176#else 177 struct sigaction act; 178 stack_t st; 179 int r; 180 181 st.ss_flags = 0; 182 st.ss_sp = alternate_signal_stack.buffer; 183 st.ss_size = sizeof alternate_signal_stack.buffer; 184 r = sigaltstack (&st, 0); 185 if (r != 0) 186 return r; 187 188 program_error_message = _("program error"); 189 stack_overflow_message = _("stack overflow"); 190 segv_action = action; 191 192 sigemptyset (&act.sa_mask); 193 194 /* POSIX 1003.1-2001 says SA_RESETHAND implies SA_NODEFER, but this 195 is not true on Solaris 8 at least. It doesn't hurt to use 196 SA_NODEFER here, so leave it in. */ 197 act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO; 198 199 act.sa_sigaction = segv_handler; 200 return sigaction (SIGSEGV, &act, 0); 201#endif 202} 203 204#if DEBUG 205 206#include <stdio.h> 207 208int volatile exit_failure; 209 210static long 211recurse (char *p) 212{ 213 char array[500]; 214 array[0] = 1; 215 return *p + recurse (array); 216} 217 218char *program_name; 219 220int 221main (int argc, char **argv) 222{ 223 program_name = argv[0]; 224 c_stack_action (c_stack_die); 225 return recurse ("\1"); 226} 227 228#endif /* DEBUG */ 229 230/* 231Local Variables: 232compile-command: "gcc -D_GNU_SOURCE -DDEBUG \ 233 -DHAVE_INTTYPES_H -DHAVE_SIGINFO_T \ 234 -DHAVE_XSI_STACK_OVERFLOW_HEURISTIC -DHAVE_UNISTD_H \ 235 -Wall -W -g c-stack.c -o c-stack" 236End: 237*/ 238