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