xref: /netbsd-src/external/gpl2/diffutils/dist/lib/c-stack.c (revision 75f6d617e282811cb173c2ccfbf5df0dd71f7045)
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