summaryrefslogtreecommitdiff
path: root/src/stackovf.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/stackovf.c')
-rw-r--r--src/stackovf.c454
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 */