diff options
Diffstat (limited to 'src/stackovf.c')
-rw-r--r-- | src/stackovf.c | 454 |
1 files changed, 0 insertions, 454 deletions
diff --git a/src/stackovf.c b/src/stackovf.c deleted file mode 100644 index 3d0468ab..00000000 --- a/src/stackovf.c +++ /dev/null @@ -1,454 +0,0 @@ -/* Detect stack overflow (when getrlimit and sigaction or sigvec are available) - Copyright (C) 1993-1994, 2006-2007, 2010, 2013-2014, 2017 Free - Software Foundation, Inc. - Jim Avera <jima@netcom.com>, October 1993. - - This file is part of GNU M4. - - GNU M4 is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - GNU M4 is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -/* Compiled only when USE_STACKOVF is defined, which itself requires - getrlimit with the RLIMIT_STACK option, and support for alternate - signal stacks using either SVR4 or BSD interfaces. - - This should compile on ANY system which supports either sigaltstack() - or sigstack(), with or without <siginfo.h> or another way to determine - the fault address. - - There is no completely portable way to determine if a SIGSEGV signal - indicates a stack overflow. The fault address can be used to infer - this. However, the fault address is passed to the signal handler in - different ways on various systems. One of three methods are used to - determine the fault address: - - 1. The siginfo parameter (with siginfo.h, i.e., SVR4). - - 2. 4th "addr" parameter (assumed if struct sigcontext is defined, - i.e., SunOS 4.x/BSD). - - 3. None (if no method is available). This case just prints a - message before aborting with a core dump. That way the user at - least knows that it *might* be a recursion problem. - - Jim Avera <jima@netcom.com> writes, on Tue, 5 Oct 93 19:27 PDT: - - "I got interested finding out how a program could catch and - diagnose its own stack overflow, and ended up modifying m4 to do - this. Now it prints a nice error message and exits. - - How it works: SIGSEGV is caught using a separate signal stack. The - signal handler declares a stack overflow if the fault address is - near the end of the stack region, or if the maximum VM address - space limit has been reached. Otherwise, it returns to re-execute - the instruction with SIG_DFL set, so that any real bugs cause a - core dump as usual." - - Jim Avera <jima@netcom.com> writes, on Fri, 24 Jun 94 12:14 PDT: - - "The stack-overflow detection code would still be needed to avoid a - SIGSEGV abort if swap space was exhausted at the moment the stack - tried to grow. This is probably unlikely to occur with the - explicit nesting limit option of GNU m4." - - Jim Avera <jima@netcom.com> writes, on Wed, 6 Jul 1994 14:41 PDT: - - "When a stack overflow occurs, a SIGSEGV signal is sent, which by - default aborts the process with a core dump. - - The code in stackovf.c catches SIGSEGV using a separate signal - stack. The signal handler determines whether or not the SIGSEGV - arose from a stack overflow. If it is a stack overflow, an - external function is called (which, in m4, prints a message an - exits). Otherwise the SIGSEGV represents an m4 bug, and the signal - is re-raised with SIG_DFL set, which results in an abort and core - dump in the usual way. It seems important (to me) that internal m4 - bugs not be reported as user recursion errors, or vice-versa." */ - -/* Define this to see runtime debug info. Implied by DEBUG. */ -/*#define DEBUG_STKOVF */ - -#include <config.h> - -#include "m4.h" - -#ifdef USE_STACKOVF - -#include <sys/time.h> -#include <sys/resource.h> - -#if HAVE_SIGINFO_H -# include <siginfo.h> -#endif - -#ifndef SA_RESETHAND -# define SA_RESETHAND 0 -#endif -#ifndef SA_SIGINFO -# define SA_SIGINFO 0 -#endif - -#ifndef SIGSTKSZ -# define SIGSTKSZ 8192 -#endif - -/* If the trap address is within STACKOVF_DETECT bytes of the calculated - stack limit, we diagnose a stack overflow. This must be large enough - to cover errors in our estimatation of the limit address, and to - account for the maximum size of local variables (the amount the - trapping reference might exceed the stack limit). Also, some machines - may report an arbitrary address within the same page frame. - If the value is too large, we might call some other SIGSEGV a stack - overflow, masking a bug. */ - -#ifndef STACKOVF_DETECT -# define STACKOVF_DETECT 16384 -#endif - -typedef void (*handler_t) (void); - -#if defined __ultrix && defined __vax -extern char *sbrk (int); -extern int getrlimit (int, struct rlimit *); -extern int sigstack (struct sigstack *, struct sigstack *); -extern int sigvec (int, struct sigvec *, struct sigvec *); -#endif - -static void *stackbuf; -static const char *stackbot; -static const char *stackend; -static const char *arg0; -static handler_t stackovf_handler; - -/* The following OS-independent procedure is called from the SIGSEGV - signal handler. The signal handler obtains information about the trap - in an OS-dependent manner, and passes a parameter with the meanings as - explained below. - - If the OS explicitly identifies a stack overflow trap, either pass - PARAM_STACKOVF if a stack overflow, or pass PARAM_NOSTACKOVF if not - (id est, it is a random bounds violation). Otherwise, if the fault - address is available, pass the fault address. Otherwise (if no - information is available), pass NULL. - - Not given an explicit indication, we compare the fault address with - the estimated stack limit, and test to see if overall VM space is - exhausted. - - If a stack overflow is identified, then the external *stackovf_handler - function is called, which should print an error message and exit. If - it is NOT a stack overflow, then we silently abort with a core dump by - returning to re-raise the SIGSEGV with SIG_DFL set. If indeterminate, - then we do not call *stackovf_handler, but instead print an ambiguous - message and abort with a core dump. This only occurs on systems which - provide no information, but is better than nothing. */ - -#define PARAM_STACKOVF ((const char *) (1 + STACKOVF_DETECT)) -#define PARAM_NOSTACKOVF ((const char *) (2 + STACKOVF_DETECT)) - -static void -process_sigsegv (int signo, const char *p) -{ - ptrdiff_t diff; - diff = (p - stackend); - -#ifdef DEBUG_STKOVF - { - char buf[200]; - - sprintf (buf, - "process_sigsegv: p=%p stackend=%p diff=%" PRIdPTR "bot=%p\n", - p, stackend, diff, stackbot); - write (2, buf, strlen (buf)); - } -#endif - - if (p != PARAM_NOSTACKOVF) - { - if ((long) sbrk (8192) == (long) -1) - { - const char *cp; - - /* sbrk failed. Assume the RLIMIT_VMEM prevents expansion even - if the stack limit has not been reached. */ - - /* FIXME - calling gettext inside a signal handler is - dangerous, since it can call malloc, which is not signal - safe. We can sort of justify it by the fact that this - handler is designed to exit() the program, but it could - really use a better fix. */ - cp = _("VMEM limit exceeded?\n"); - write (2, cp, strlen (cp)); - p = PARAM_STACKOVF; - } - if (diff >= -STACKOVF_DETECT && diff <= STACKOVF_DETECT) - { - - /* The fault address is "sufficiently close" to the stack lim. */ - - p = PARAM_STACKOVF; - } - if (p == PARAM_STACKOVF) - { - - /* We have determined that this is indeed a stack overflow. */ - - (*stackovf_handler) (); /* should call exit() */ - } - } - if (p == NULL) - { - const char *cp; - - /* FIXME - calling gettext inside a signal handler is dangerous, - since it can call malloc, which is not signal safe. */ - cp = _("\ -Memory bounds violation detected (SIGSEGV). Either a stack overflow\n\ -occurred, or there is a bug in "); - write (2, cp, strlen (cp)); - write (2, arg0, strlen (arg0)); - cp = _(". Check for possible infinite recursion.\n"); - write (2, cp, strlen (cp)); - } - - /* Return to re-execute the instruction which caused the trap with - SIGSEGV set to SIG_DFL. An abort with core dump should occur. */ - - signal (signo, SIG_DFL); -} - -#if HAVE_STRUCT_SIGACTION_SA_SIGACTION - -/* POSIX. */ - -static void -sigsegv_handler (int signo, siginfo_t *ip, void *context) -{ - process_sigsegv - (signo, (ip != NULL - && ip->si_signo == SIGSEGV ? (char *) ip->si_addr : NULL)); -} - -#elif HAVE_SIGINFO_T - -/* SVR4. */ - -static void -sigsegv_handler (int signo, siginfo_t *ip) -{ - process_sigsegv - (signo, (ip != NULL - && ip->si_signo == SIGSEGV ? (char *) ip->si_addr : NULL)); -} - -#elif HAVE_SIGCONTEXT - -/* SunOS 4.x (and BSD?). (not tested) */ - -static void -sigsegv_handler (int signo, int code, struct sigcontext *scp, char *addr) -{ - process_sigsegv (signo, addr); -} - -#else /* not HAVE_SIGCONTEXT */ - -/* OS provides no information. */ - -static void -sigsegv_handler (int signo) -{ - process_sigsegv (signo, NULL); -} - -#endif /* not HAVE_SIGCONTEXT */ - -/* Arrange to trap a stack-overflow and call a specified handler. The - call is on a dedicated signal stack. - - argv and envp are as passed to main. - - If a stack overflow is not detected, then the SIGSEGV is re-raised - with action set to SIG_DFL, causing an abort and coredump in the usual - way. - - Detection of a stack overflow depends on the trap address being near - the stack limit address. The stack limit cannot be directly - determined in a portable way, but we make an estimate based on the - address of the argv and environment vectors, their contents, and the - maximum stack size obtained using getrlimit. */ - -void -setup_stackovf_trap (char *const *argv, char *const *envp, handler_t handler) -{ - struct rlimit rl; - rlim_t stack_len; - int grows_upward; - register char *const *v; - register char *p; -#if HAVE_SIGACTION && defined SA_ONSTACK - struct sigaction act; -#elif HAVE_SIGVEC && defined SV_ONSTACK - struct sigvec vec; -#else - -Error - Do not know how to set up stack-ovf trap handler... - -#endif - - arg0 = argv[0]; - stackovf_handler = handler; - - /* Calculate the approximate expected addr for a stack-ovf trap. */ - - if (getrlimit (RLIMIT_STACK, &rl) < 0) - error (EXIT_FAILURE, errno, _("getrlimit")); - stack_len = (rl.rlim_cur < rl.rlim_max ? rl.rlim_cur : rl.rlim_max); - stackbot = (char *) argv; - grows_upward = ((char *) &stack_len > stackbot); - if (grows_upward) - { - - /* Grows toward increasing addresses. */ - - for (v = argv; (p = (char *) *v) != NULL; v++) - { - if (p < stackbot) - stackbot = p; - } - if ((char *) envp < stackbot) - stackbot = (char *) envp; - for (v = envp; (p = (char *) *v) != NULL; v++) - { - if (p < stackbot) - stackbot = p; - } - stackend = stackbot + stack_len; - } - else - { - - /* The stack grows "downward" (toward decreasing addresses). */ - - for (v = argv; (p = (char *) *v) != NULL; v++) - { - if (p > stackbot) - stackbot = p; - } - if ((char *) envp > stackbot) - stackbot = (char *) envp; - for (v = envp; (p = (char *) *v) != NULL; v++) - { - if (p > stackbot) - stackbot = p; - } - stackend = stackbot - stack_len; - } - - /* Allocate a separate signal-handler stack. */ - -#if HAVE_SIGALTSTACK && (HAVE_SIGINFO_T || ! HAVE_SIGSTACK) - - /* Use sigaltstack only if siginfo_t is available, unless there is no - choice. */ - - { - stack_t ss; -# ifndef HAVE_STACK_T_SS_SP - /* This workaround is for BSD/OS 4.0.1: - http://lists.gnu.org/archive/html/bug-m4/2006-12/msg00004.html */ -# define ss_sp ss_base -# endif /* ! HAVE_STACK_T_SS_SP */ - - stackbuf = xmalloc (SIGSTKSZ); - - ss.ss_size = SIGSTKSZ; - ss.ss_sp = stackbuf; - ss.ss_flags = 0; - if (sigaltstack (&ss, NULL) < 0) - { - /* Oops - sigstack exists but doesn't work. We can't install - the overflow detector, but should gracefully treat it as - though sigstack doesn't exist. For example, this happens - when compiled with Linux 2.1 headers but run against Linux - 2.0 kernel. */ - free (stackbuf); - if (errno == ENOSYS) - return; - error (EXIT_FAILURE, errno, _("sigaltstack")); - } - } - -#elif HAVE_SIGSTACK - - { - struct sigstack ss; - stackbuf = xmalloc (2 * SIGSTKSZ); - - ss.ss_sp = stackbuf + SIGSTKSZ; - ss.ss_onstack = 0; - if (sigstack (&ss, NULL) < 0) - { - /* Oops - sigstack exists but doesn't work. We can't install - the overflow detector, but should gracefully treat it as - though sigstack doesn't exist. For example, this happens - when compiled with Linux 2.1 headers but run against Linux - 2.0 kernel. */ - free (stackbuf); - if (errno == ENOSYS) - return; - error (EXIT_FAILURE, errno, _("sigstack")); - } - } - -#else /* not HAVE_SIGSTACK */ - -Error - Do not know how to set up stack-ovf trap handler... - -#endif /* not HAVE_SIGSTACK */ - - /* Arm the SIGSEGV signal handler. */ - -#if HAVE_SIGACTION && defined SA_ONSTACK - - sigaction (SIGSEGV, NULL, &act); -# if HAVE_STRUCT_SIGACTION_SA_SIGACTION - act.sa_sigaction = sigsegv_handler; -# else /* ! HAVE_STRUCT_SIGACTION_SA_SIGACTION */ - act.sa_handler = (RETSIGTYPE (*) (int)) sigsegv_handler; -# endif /* ! HAVE_STRUCT_SIGACTION_SA_SIGACTION */ - sigemptyset (&act.sa_mask); - act.sa_flags = (SA_ONSTACK | SA_RESETHAND | SA_SIGINFO); - if (sigaction (SIGSEGV, &act, NULL) < 0) - error (EXIT_FAILURE, errno, _("sigaction")); - -#else /* ! HAVE_SIGACTION */ - - vec.sv_handler = (RETSIGTYPE (*) (int)) sigsegv_handler; - vec.sv_mask = 0; - vec.sv_flags = (SV_ONSTACK | SV_RESETHAND); - if (sigvec (SIGSEGV, &vec, NULL) < 0) - error (EXIT_FAILURE, errno, _("sigvec")); - -#endif /* ! HAVE_SIGACTION */ - -} - -void -stackovf_exit (void) -{ - DELETE (stackbuf); -} - -#endif /* USE_STACKOVF */ |