118fd37a7SXin LI /* Stack overflow handling.
218fd37a7SXin LI
318fd37a7SXin LI Copyright (C) 2002, 2004 Free Software Foundation, Inc.
418fd37a7SXin LI
518fd37a7SXin LI This program is free software; you can redistribute it and/or modify
618fd37a7SXin LI it under the terms of the GNU General Public License as published by
718fd37a7SXin LI the Free Software Foundation; either version 2, or (at your option)
818fd37a7SXin LI any later version.
918fd37a7SXin LI
1018fd37a7SXin LI This program is distributed in the hope that it will be useful,
1118fd37a7SXin LI but WITHOUT ANY WARRANTY; without even the implied warranty of
1218fd37a7SXin LI MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1318fd37a7SXin LI GNU General Public License for more details.
1418fd37a7SXin LI
1518fd37a7SXin LI You should have received a copy of the GNU General Public License
1618fd37a7SXin LI along with this program; if not, write to the Free Software Foundation,
1718fd37a7SXin LI Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
1818fd37a7SXin LI
1918fd37a7SXin LI /* Written by Paul Eggert. */
2018fd37a7SXin LI
2118fd37a7SXin LI /* NOTES:
2218fd37a7SXin LI
2318fd37a7SXin LI A program that uses alloca, dynamic arrays, or large local
2418fd37a7SXin LI variables may extend the stack by more than a page at a time. If
2518fd37a7SXin LI so, when the stack overflows the operating system may not detect
2618fd37a7SXin LI the overflow until the program uses the array, and this module may
2718fd37a7SXin LI incorrectly report a program error instead of a stack overflow.
2818fd37a7SXin LI
2918fd37a7SXin LI To avoid this problem, allocate only small objects on the stack; a
3018fd37a7SXin LI program should be OK if it limits single allocations to a page or
3118fd37a7SXin LI less. Allocate larger arrays in static storage, or on the heap
3218fd37a7SXin LI (e.g., with malloc). Yes, this is a pain, but we don't know of any
3318fd37a7SXin LI better solution that is portable.
3418fd37a7SXin LI
3518fd37a7SXin LI No attempt has been made to deal with multithreaded applications. */
3618fd37a7SXin LI
3718fd37a7SXin LI #if HAVE_CONFIG_H
3818fd37a7SXin LI # include <config.h>
3918fd37a7SXin LI #endif
4018fd37a7SXin LI
4118fd37a7SXin LI #ifndef __attribute__
4218fd37a7SXin LI # if __GNUC__ < 3 || __STRICT_ANSI__
4318fd37a7SXin LI # define __attribute__(x)
4418fd37a7SXin LI # endif
4518fd37a7SXin LI #endif
4618fd37a7SXin LI
4718fd37a7SXin LI #include "gettext.h"
4818fd37a7SXin LI #define _(msgid) gettext (msgid)
4918fd37a7SXin LI
5018fd37a7SXin LI #include <errno.h>
5118fd37a7SXin LI #ifndef ENOTSUP
5218fd37a7SXin LI # define ENOTSUP EINVAL
5318fd37a7SXin LI #endif
5418fd37a7SXin LI #ifndef EOVERFLOW
5518fd37a7SXin LI # define EOVERFLOW EINVAL
5618fd37a7SXin LI #endif
5718fd37a7SXin LI
5818fd37a7SXin LI #include <signal.h>
5918fd37a7SXin LI #if ! HAVE_STACK_T && ! defined stack_t
6018fd37a7SXin LI typedef struct sigaltstack stack_t;
6118fd37a7SXin LI #endif
6218fd37a7SXin LI
6318fd37a7SXin LI #include <stdlib.h>
6418fd37a7SXin LI #include <string.h>
6518fd37a7SXin LI
6618fd37a7SXin LI #if HAVE_SYS_RESOURCE_H
6718fd37a7SXin LI /* Include sys/time.h here, because...
6818fd37a7SXin LI SunOS-4.1.x <sys/resource.h> fails to include <sys/time.h>.
6918fd37a7SXin LI This gives "incomplete type" errors for ru_utime and tu_stime. */
7018fd37a7SXin LI # if HAVE_SYS_TIME_H
7118fd37a7SXin LI # include <sys/time.h>
7218fd37a7SXin LI # endif
7318fd37a7SXin LI # include <sys/resource.h>
7418fd37a7SXin LI #endif
7518fd37a7SXin LI
7618fd37a7SXin LI #if HAVE_UCONTEXT_H
7718fd37a7SXin LI # include <ucontext.h>
7818fd37a7SXin LI #endif
7918fd37a7SXin LI
8018fd37a7SXin LI #if HAVE_UNISTD_H
8118fd37a7SXin LI # include <unistd.h>
8218fd37a7SXin LI #endif
8318fd37a7SXin LI #ifndef STDERR_FILENO
8418fd37a7SXin LI # define STDERR_FILENO 2
8518fd37a7SXin LI #endif
8618fd37a7SXin LI
8718fd37a7SXin LI #if DEBUG
8818fd37a7SXin LI # include <stdio.h>
8918fd37a7SXin LI #endif
9018fd37a7SXin LI
9118fd37a7SXin LI #include "c-stack.h"
9218fd37a7SXin LI #include "exitfail.h"
9318fd37a7SXin LI
9418fd37a7SXin LI #if (HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined SA_NODEFER \
9518fd37a7SXin LI && defined SA_ONSTACK && defined SA_RESETHAND && defined SA_SIGINFO)
9618fd37a7SXin LI # define SIGACTION_WORKS 1
9718fd37a7SXin LI #else
9818fd37a7SXin LI # define SIGACTION_WORKS 0
9918fd37a7SXin LI #endif
10018fd37a7SXin LI
10118fd37a7SXin LI extern char *program_name;
10218fd37a7SXin LI
10318fd37a7SXin LI /* The user-specified action to take when a SEGV-related program error
10418fd37a7SXin LI or stack overflow occurs. */
10518fd37a7SXin LI static void (* volatile segv_action) (int);
10618fd37a7SXin LI
10718fd37a7SXin LI /* Translated messages for program errors and stack overflow. Do not
10818fd37a7SXin LI translate them in the signal handler, since gettext is not
10918fd37a7SXin LI async-signal-safe. */
11018fd37a7SXin LI static char const * volatile program_error_message;
11118fd37a7SXin LI static char const * volatile stack_overflow_message;
11218fd37a7SXin LI
11318fd37a7SXin LI /* Output an error message, then exit with status EXIT_FAILURE if it
11418fd37a7SXin LI appears to have been a stack overflow, or with a core dump
11518fd37a7SXin LI otherwise. This function is async-signal-safe. */
11618fd37a7SXin LI
11718fd37a7SXin LI static void die (int) __attribute__ ((noreturn));
11818fd37a7SXin LI static void
die(int signo)11918fd37a7SXin LI die (int signo)
12018fd37a7SXin LI {
12118fd37a7SXin LI char const *message;
12218fd37a7SXin LI segv_action (signo);
12318fd37a7SXin LI message = signo ? program_error_message : stack_overflow_message;
12418fd37a7SXin LI write (STDERR_FILENO, program_name, strlen (program_name));
12518fd37a7SXin LI write (STDERR_FILENO, ": ", 2);
12618fd37a7SXin LI write (STDERR_FILENO, message, strlen (message));
12718fd37a7SXin LI write (STDERR_FILENO, "\n", 1);
12818fd37a7SXin LI if (! signo)
12918fd37a7SXin LI _exit (exit_failure);
13018fd37a7SXin LI kill (getpid (), signo);
13118fd37a7SXin LI abort ();
13218fd37a7SXin LI }
13318fd37a7SXin LI
13418fd37a7SXin LI #if HAVE_SIGALTSTACK && HAVE_DECL_SIGALTSTACK
13518fd37a7SXin LI
13618fd37a7SXin LI /* Direction of the C runtime stack. This function is
13718fd37a7SXin LI async-signal-safe. */
13818fd37a7SXin LI
13918fd37a7SXin LI # if STACK_DIRECTION
14018fd37a7SXin LI # define find_stack_direction(ptr) STACK_DIRECTION
14118fd37a7SXin LI # else
14218fd37a7SXin LI static int
find_stack_direction(char const * addr)14318fd37a7SXin LI find_stack_direction (char const *addr)
14418fd37a7SXin LI {
14518fd37a7SXin LI char dummy;
14618fd37a7SXin LI return ! addr ? find_stack_direction (&dummy) : addr < &dummy ? 1 : -1;
14718fd37a7SXin LI }
14818fd37a7SXin LI # endif
14918fd37a7SXin LI
15018fd37a7SXin LI /* Storage for the alternate signal stack. */
15118fd37a7SXin LI static union
15218fd37a7SXin LI {
15318fd37a7SXin LI char buffer[SIGSTKSZ];
15418fd37a7SXin LI
15518fd37a7SXin LI /* These other members are for proper alignment. There's no
15618fd37a7SXin LI standard way to guarantee stack alignment, but this seems enough
15718fd37a7SXin LI in practice. */
15818fd37a7SXin LI long double ld;
15918fd37a7SXin LI long l;
16018fd37a7SXin LI void *p;
16118fd37a7SXin LI } alternate_signal_stack;
16218fd37a7SXin LI
16318fd37a7SXin LI # if SIGACTION_WORKS
16418fd37a7SXin LI
16518fd37a7SXin LI /* Handle a segmentation violation and exit. This function is
16618fd37a7SXin LI async-signal-safe. */
16718fd37a7SXin LI
16818fd37a7SXin LI static void segv_handler (int, siginfo_t *, void *) __attribute__((noreturn));
16918fd37a7SXin LI static void
segv_handler(int signo,siginfo_t * info,void * context)17018fd37a7SXin LI segv_handler (int signo, siginfo_t *info,
17118fd37a7SXin LI void *context __attribute__ ((unused)))
17218fd37a7SXin LI {
17318fd37a7SXin LI /* Clear SIGNO if it seems to have been a stack overflow. */
17418fd37a7SXin LI if (0 < info->si_code)
17518fd37a7SXin LI {
17618fd37a7SXin LI # if ! HAVE_XSI_STACK_OVERFLOW_HEURISTIC
17718fd37a7SXin LI /* We can't easily determine whether it is a stack overflow; so
17818fd37a7SXin LI assume that the rest of our program is perfect (!) and that
17918fd37a7SXin LI this segmentation violation is a stack overflow. */
18018fd37a7SXin LI signo = 0;
18118fd37a7SXin LI # else
18218fd37a7SXin LI /* If the faulting address is within the stack, or within one
18318fd37a7SXin LI page of the stack end, assume that it is a stack
18418fd37a7SXin LI overflow. */
18518fd37a7SXin LI ucontext_t const *user_context = context;
18618fd37a7SXin LI char const *stack_base = user_context->uc_stack.ss_sp;
18718fd37a7SXin LI size_t stack_size = user_context->uc_stack.ss_size;
18818fd37a7SXin LI char const *faulting_address = info->si_addr;
18918fd37a7SXin LI size_t s = faulting_address - stack_base;
19018fd37a7SXin LI size_t page_size = sysconf (_SC_PAGESIZE);
19118fd37a7SXin LI if (find_stack_direction (0) < 0)
19218fd37a7SXin LI s += page_size;
19318fd37a7SXin LI if (s < stack_size + page_size)
19418fd37a7SXin LI signo = 0;
19518fd37a7SXin LI
19618fd37a7SXin LI # if DEBUG
19718fd37a7SXin LI {
19818fd37a7SXin LI char buf[1024];
19918fd37a7SXin LI sprintf (buf,
20018fd37a7SXin LI "segv_handler fault=%p base=%p size=%lx page=%lx signo=%d\n",
20118fd37a7SXin LI faulting_address, stack_base, (unsigned long) stack_size,
20218fd37a7SXin LI (unsigned long) page_size, signo);
20318fd37a7SXin LI write (STDERR_FILENO, buf, strlen (buf));
20418fd37a7SXin LI }
20518fd37a7SXin LI # endif
20618fd37a7SXin LI # endif
20718fd37a7SXin LI }
20818fd37a7SXin LI
20918fd37a7SXin LI die (signo);
21018fd37a7SXin LI }
21118fd37a7SXin LI # endif
21218fd37a7SXin LI
21318fd37a7SXin LI static void
null_action(int signo)21418fd37a7SXin LI null_action (int signo __attribute__ ((unused)))
21518fd37a7SXin LI {
21618fd37a7SXin LI }
21718fd37a7SXin LI
21818fd37a7SXin LI /* Set up ACTION so that it is invoked on C stack overflow. Return -1
21918fd37a7SXin LI (setting errno) if this cannot be done.
22018fd37a7SXin LI
22118fd37a7SXin LI When ACTION is called, it is passed an argument equal to SIGSEGV
22218fd37a7SXin LI for a segmentation violation that does not appear related to stack
22318fd37a7SXin LI overflow, and is passed zero otherwise. On many platforms it is
22418fd37a7SXin LI hard to tell; when in doubt, zero is passed.
22518fd37a7SXin LI
22618fd37a7SXin LI A null ACTION acts like an action that does nothing.
22718fd37a7SXin LI
22818fd37a7SXin LI ACTION must be async-signal-safe. ACTION together with its callees
22918fd37a7SXin LI must not require more than SIGSTKSZ bytes of stack space. */
23018fd37a7SXin LI
23118fd37a7SXin LI int
c_stack_action(void (* action)(int))23218fd37a7SXin LI c_stack_action (void (*action) (int))
23318fd37a7SXin LI {
23418fd37a7SXin LI int r;
23518fd37a7SXin LI stack_t st;
23618fd37a7SXin LI st.ss_flags = 0;
23718fd37a7SXin LI st.ss_sp = alternate_signal_stack.buffer;
23818fd37a7SXin LI st.ss_size = sizeof alternate_signal_stack.buffer;
23918fd37a7SXin LI r = sigaltstack (&st, 0);
24018fd37a7SXin LI if (r != 0)
24118fd37a7SXin LI return r;
24218fd37a7SXin LI
24318fd37a7SXin LI segv_action = action ? action : null_action;
24418fd37a7SXin LI program_error_message = _("program error");
24518fd37a7SXin LI stack_overflow_message = _("stack overflow");
24618fd37a7SXin LI
24718fd37a7SXin LI {
24818fd37a7SXin LI # if SIGACTION_WORKS
24918fd37a7SXin LI struct sigaction act;
25018fd37a7SXin LI sigemptyset (&act.sa_mask);
25118fd37a7SXin LI
25218fd37a7SXin LI /* POSIX 1003.1-2001 says SA_RESETHAND implies SA_NODEFER, but
25318fd37a7SXin LI this is not true on Solaris 8 at least. It doesn't hurt to use
25418fd37a7SXin LI SA_NODEFER here, so leave it in. */
25518fd37a7SXin LI act.sa_flags = SA_NODEFER | SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
25618fd37a7SXin LI
25718fd37a7SXin LI act.sa_sigaction = segv_handler;
25818fd37a7SXin LI
25918fd37a7SXin LI return sigaction (SIGSEGV, &act, 0);
26018fd37a7SXin LI # else
26118fd37a7SXin LI return signal (SIGSEGV, die) == SIG_ERR ? -1 : 0;
26218fd37a7SXin LI # endif
26318fd37a7SXin LI }
26418fd37a7SXin LI }
26518fd37a7SXin LI
26618fd37a7SXin LI #else /* ! (HAVE_SIGALTSTACK && HAVE_DECL_SIGALTSTACK) */
26718fd37a7SXin LI
26818fd37a7SXin LI int
c_stack_action(void (* action)(int))26918fd37a7SXin LI c_stack_action (void (*action) (int) __attribute__ ((unused)))
27018fd37a7SXin LI {
27118fd37a7SXin LI errno = ENOTSUP;
27218fd37a7SXin LI return -1;
27318fd37a7SXin LI }
27418fd37a7SXin LI
27518fd37a7SXin LI #endif
27618fd37a7SXin LI
27718fd37a7SXin LI
27818fd37a7SXin LI
27918fd37a7SXin LI #if DEBUG
28018fd37a7SXin LI
28118fd37a7SXin LI int volatile exit_failure;
28218fd37a7SXin LI
28318fd37a7SXin LI static long
recurse(char * p)28418fd37a7SXin LI recurse (char *p)
28518fd37a7SXin LI {
28618fd37a7SXin LI char array[500];
28718fd37a7SXin LI array[0] = 1;
28818fd37a7SXin LI return *p + recurse (array);
28918fd37a7SXin LI }
29018fd37a7SXin LI
29118fd37a7SXin LI char *program_name;
29218fd37a7SXin LI
29318fd37a7SXin LI int
main(int argc,char ** argv)29418fd37a7SXin LI main (int argc __attribute__ ((unused)), char **argv)
29518fd37a7SXin LI {
29618fd37a7SXin LI program_name = argv[0];
29718fd37a7SXin LI fprintf (stderr,
29818fd37a7SXin LI "The last output line should contain \"stack overflow\".\n");
29918fd37a7SXin LI if (c_stack_action (0) == 0)
30018fd37a7SXin LI return recurse ("\1");
30118fd37a7SXin LI perror ("c_stack_action");
30218fd37a7SXin LI return 1;
30318fd37a7SXin LI }
30418fd37a7SXin LI
30518fd37a7SXin LI #endif /* DEBUG */
30618fd37a7SXin LI
30718fd37a7SXin LI /*
30818fd37a7SXin LI Local Variables:
30918fd37a7SXin LI compile-command: "gcc -DDEBUG -DHAVE_CONFIG_H -I.. -g -O -Wall -W c-stack.c"
31018fd37a7SXin LI End:
31118fd37a7SXin LI */
312