m4-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

detecting stack overflow


From: Eric Blake
Subject: detecting stack overflow
Date: Thu, 05 Jun 2008 07:33:42 -0600
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.14) Gecko/20080421 Thunderbird/2.0.0.14 Mnenhy/0.7.5.666

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

I'm working on improving stack overflow detection.  Attached is a patch
that swaps from our hand-rolled stackovf.c to gnulib's c-stack module,
which means less maintenance for us.  It also makes -L unlimited on
platforms where stack overflow is detectable, rather than arbitrarily
limited to 1024.  In addition to the eased maintenance burden, my testing
showed that c-stack behaved better than stackovf at detecting stack
overflow on Linux, so it is a definite improvement.  However, gnulib's
module appears to lack the fallback to sigstack that stackovf.c supported
for older platforms that lack sigaltstack.  Also, gnulib's module is no
better than stackovf at overflow detection on cygwin, where sigstack and
sigalstack are both lacking, even though libsigsegv handles cygwin just
fine.  So I'd still like to enhance this to use libsigsegv when it is
present, falling back to c-stack if not, and see whether anything in our
stackovf.c should be folded into gnulib's c-stack.

The other issue is that for the master branch, this belongs in the same
category as getopt_long - it should be compiled for use by main.c, but
does not need to bloat libgnu pulled in by modules.  There, I would like
to figure out how to have two parallel gnulib libraries, rather than our
current approach of one library and a set of hand-imported files.  I've
looked at it on and off in the past, but never committed anything.  But
before I can apply this patch to the branch, I have to have a working
scenario so that it can also be ported to the master.

At any rate, here's the patch for playing with.  Should I create a new
branch in m4.git with this patch (and subsequent patches for libsigsegv),
to make it easier for others to play with this branch until it is ready to
merge into mainline branch-1.6?

- --
Don't work too hard, make some time for fun as well!

Eric Blake             address@hidden
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkhH6zYACgkQ84KuGfSFAYA6gwCgkVlHrwAxBXhmCw1IhdRUQ9S0
ZuIAoKb9qLXk0/wqX2bXiDUoGlh5nzSF
=/Owa
-----END PGP SIGNATURE-----
>From ba8a7b28a5a933d9a7d47390b432c6caab87d371 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Thu, 5 Jun 2008 07:08:58 -0600
Subject: [PATCH] Replace stackovf with gnulib c-stack.

* m4/gnulib.cache.m4: Import c-stack module.
* configure.ac (AC_CHECK_HEADERS_ONCE): Remove check for
siginfo.h, sys/wait.h.
(AC_CHECK_TYPES): Likewise for siginfo_t.
(AC_CHECK_MEMBERS): Likewise for sa_sigaction, ss_sp.
(AC_CHECK_FUNCS_ONCE): Likewise for sigaction, sigaltstack,
sigstack, sigvec, strerror.
(M4_cv_use_stackovf): Likewise for stack overflow detection.
* src/Makefile.am (m4_SOURCES): Don't build stackovf.c.
* src/stackovf.c: Delete.
* src/m4.h (setup_stackovf_trap): Delete.
* src/m4.c (stackovf_handler): Delete.
(main): Use c_stack_action instead of setup_stackovf_trap.  If
stack overflow is detectable, don't limit -L artificially.
(usage): Document unlimited default on supported systems.
* doc/m4.texinfo (Limits control): Document default nesting
limit.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog          |   21 +++
 NEWS               |    3 +
 configure.ac       |   58 -------
 doc/m4.texinfo     |    3 +-
 m4/gnulib-cache.m4 |    4 +-
 src/Makefile.am    |    3 -
 src/m4.c           |   27 +---
 src/m4.h           |    4 -
 src/stackovf.c     |  423 ----------------------------------------------------
 9 files changed, 34 insertions(+), 512 deletions(-)
 delete mode 100644 src/stackovf.c

diff --git a/ChangeLog b/ChangeLog
index adc0364..fde7a70 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+2008-06-05  Eric Blake  <address@hidden>
+
+       Replace stackovf with gnulib c-stack.
+       * m4/gnulib.cache.m4: Import c-stack module.
+       * configure.ac (AC_CHECK_HEADERS_ONCE): Remove check for
+       siginfo.h, sys/wait.h.
+       (AC_CHECK_TYPES): Likewise for siginfo_t.
+       (AC_CHECK_MEMBERS): Likewise for sa_sigaction, ss_sp.
+       (AC_CHECK_FUNCS_ONCE): Likewise for sigaction, sigaltstack,
+       sigstack, sigvec, strerror.
+       (M4_cv_use_stackovf): Likewise for stack overflow detection.
+       * src/Makefile.am (m4_SOURCES): Don't build stackovf.c.
+       * src/stackovf.c: Delete.
+       * src/m4.h (setup_stackovf_trap): Delete.
+       * src/m4.c (stackovf_handler): Delete.
+       (main): Use c_stack_action instead of setup_stackovf_trap.  If
+       stack overflow is detectable, don't limit -L artificially.
+       (usage): Document unlimited default on supported systems.
+       * doc/m4.texinfo (Limits control): Document default nesting
+       limit.
+
 2008-06-03  Eric Blake  <address@hidden>
 
        Use progname module rather than rolling our own program_name.
diff --git a/NEWS b/NEWS
index bdb7665..5aae856 100644
--- a/NEWS
+++ b/NEWS
@@ -37,6 +37,9 @@ Foundation, Inc.
    then apply this patch:
      http://git.sv.gnu.org/gitweb/?p=autoconf.git;a=commitdiff;h=56d42fa71
 
+** The `-L'/`--nesting-limit' command-line option now defaults to 0 for
+   unlimited on platforms that can detect and deal with stack overflow.
+
 ** The `defn' builtin now warns when operating on an undefined macro name.
    To simulate 1.4.x behavior, use:
      pushdef(`defn', `ifdef(`$1', `builtin(`defn', `$1')')')
diff --git a/configure.ac b/configure.ac
index ea4e130..3fb059b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -32,27 +32,8 @@ AC_CONFIG_HEADERS([lib/config.h:lib/config.hin])
 AC_PROG_CC
 M4_EARLY
 
-AC_CHECK_HEADERS_ONCE([siginfo.h sys/wait.h])
-AC_CHECK_TYPES([siginfo_t], [], [],
-[[#include <signal.h>
-#if HAVE_SIGINFO_H
-# include <siginfo.h>
-#endif
-]])
-AC_CHECK_MEMBERS([struct sigaction.sa_sigaction], [], [],
-[[#include <signal.h>
-]])
-AC_CHECK_MEMBERS([stack_t.ss_sp], [], [],
-[[#include <signal.h>
-#if HAVE_SIGINFO_H
-# include <siginfo.h>
-#endif
-]])
-
 AC_TYPE_SIGNAL
 
-AC_CHECK_FUNCS_ONCE([sigaction sigaltstack sigstack sigvec strerror])
-
 # Tandem/NSK is broken - it has 'long long int' but not
 # 'unsigned long long int', which confuses assumptions made by gnulib.
 # Simply pretend that neither type exists if both do not work.
@@ -67,45 +48,6 @@ fi
 
 M4_INIT
 
-# Code from Jim Avera <address@hidden>.
-# stackovf.c requires:
-#  1. Either sigaction with SA_ONSTACK, or sigvec with SV_ONSTACK
-#  2. Either sigaltstack or sigstack
-#  3. getrlimit, including support for RLIMIT_STACK
-AC_CACHE_CHECK([if stack overflow is detectable], [M4_cv_use_stackovf],
-[M4_cv_use_stackovf=no
-if test "$ac_cv_func_sigaction" = yes || test "$ac_cv_func_sigvec" = yes; then
-  if test "$ac_cv_func_sigaltstack" = yes || test "$ac_cv_func_sigstack" = 
yes; then
-    AC_LINK_IFELSE([AC_LANG_PROGRAM([[
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <signal.h>
-]], [[struct rlimit r; getrlimit (RLIMIT_STACK, &r);
-#if (!defined(HAVE_SIGACTION) || !defined(SA_ONSTACK)) \
-    && (!defined(HAVE_SIGVEC) || !defined(SV_ONSTACK))
-choke me               /* SA_ONSTACK and/or SV_ONSTACK are not defined */
-#endif
-]])], [M4_cv_use_stackovf=yes])
-  fi
-fi])
-AM_CONDITIONAL([STACKOVF], [test "$M4_cv_use_stackovf" = yes])
-if test "$M4_cv_use_stackovf" = yes; then
-  AC_DEFINE([USE_STACKOVF], [1],
-    [Define to 1 if using stack overflow detection])
-  AC_CHECK_TYPES([rlim_t], [],
-    [AC_DEFINE([rlim_t], [int],
-      [Define to int if rlim_t is not defined in sys/resource.h])],
-    [[#include <sys/resource.h>
-  ]])
-  AC_CHECK_TYPES([stack_t], [],
-    [AC_DEFINE([stack_t], [struct sigaltstack],
-      [Define to struct sigaltstack if stack_t is not in signal.h])],
-    [[#include <signal.h>
-  ]])
-  AC_CHECK_TYPES([sigcontext], [], [], [[#include <signal.h>
-  ]])
-fi
-
 AC_CACHE_CHECK([if system() agrees with pclose()],
   [M4_cv_func_system_consistent],
   [AC_RUN_IFELSE([AC_LANG_PROGRAM([
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index fe429b4..4692122 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -762,7 +762,8 @@ increase this value, unless you define an excessive number 
of macros.
 @cindex limit, nesting
 Artificially limit the nesting of macro calls to @var{NUM} levels,
 stopping program execution if this limit is ever exceeded.  When not
-specified, nesting is limited to 1024 levels.  A value of zero means
+specified, nesting is unlimited on platforms that can detect stack
+overflow, and limited to 1024 levels otherwise.  A value of zero means
 unlimited; but then heavily nested code could potentially cause a stack
 overflow.
 
diff --git a/m4/gnulib-cache.m4 b/m4/gnulib-cache.m4
index 5aa4820..7c1fb0d 100644
--- a/m4/gnulib-cache.m4
+++ b/m4/gnulib-cache.m4
@@ -15,11 +15,11 @@
 
 
 # Specification in the form of a command-line invocation:
-#   gnulib-tool --import --dir=. --local-dir=local --lib=libm4 
--source-base=lib --m4-base=m4 --doc-base=doc --aux-dir=build-aux --with-tests 
--no-libtool --macro-prefix=M4 announce-gen assert autobuild avltree-oset 
binary-io clean-temp cloexec close-stream closein config-h error fdl fflush 
flexmember fopen-safer fseeko gendocs getopt git-version-gen gnumakefile 
gnupload gpl-3.0 intprops memchr2 memmem mkstemp obstack progname quote regex 
stdbool stdint stdlib-safer strtod strtol unlocked-io vasnprintf-posix verror 
version-etc version-etc-fsf xalloc xmemdup0 xprintf xvasprintf-posix
+#   gnulib-tool --import --dir=. --local-dir=local --lib=libm4 
--source-base=lib --m4-base=m4 --doc-base=doc --aux-dir=build-aux --with-tests 
--no-libtool --macro-prefix=M4 announce-gen assert autobuild avltree-oset 
binary-io c-stack clean-temp cloexec close-stream closein config-h error fdl 
fflush flexmember fopen-safer fseeko gendocs getopt git-version-gen gnumakefile 
gnupload gpl-3.0 intprops memchr2 memmem mkstemp obstack progname quote regex 
stdbool stdint stdlib-safer strtod strtol unlocked-io vasnprintf-posix verror 
version-etc version-etc-fsf xalloc xmemdup0 xprintf xvasprintf-posix
 
 # Specification in the form of a few gnulib-tool.m4 macro invocations:
 gl_LOCAL_DIR([local])
-gl_MODULES([announce-gen assert autobuild avltree-oset binary-io clean-temp 
cloexec close-stream closein config-h error fdl fflush flexmember fopen-safer 
fseeko gendocs getopt git-version-gen gnumakefile gnupload gpl-3.0 intprops 
memchr2 memmem mkstemp obstack progname quote regex stdbool stdint stdlib-safer 
strtod strtol unlocked-io vasnprintf-posix verror version-etc version-etc-fsf 
xalloc xmemdup0 xprintf xvasprintf-posix])
+gl_MODULES([announce-gen assert autobuild avltree-oset binary-io c-stack 
clean-temp cloexec close-stream closein config-h error fdl fflush flexmember 
fopen-safer fseeko gendocs getopt git-version-gen gnumakefile gnupload gpl-3.0 
intprops memchr2 memmem mkstemp obstack progname quote regex stdbool stdint 
stdlib-safer strtod strtol unlocked-io vasnprintf-posix verror version-etc 
version-etc-fsf xalloc xmemdup0 xprintf xvasprintf-posix])
 gl_AVOID([])
 gl_SOURCE_BASE([lib])
 gl_M4_BASE([m4])
diff --git a/src/Makefile.am b/src/Makefile.am
index f2c1524..900f8ea 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -24,7 +24,4 @@ AM_CPPFLAGS = -I$(top_srcdir)/lib -I../lib
 bin_PROGRAMS = m4
 m4_SOURCES = m4.h m4.c builtin.c debug.c eval.c format.c freeze.c input.c \
 macro.c output.c path.c symtab.c
-if STACKOVF
-m4_SOURCES += stackovf.c
-endif
 m4_LDADD = ../lib/libm4.a $(LIBM4_LIBDEPS) $(POW_LIB)
diff --git a/src/m4.c b/src/m4.c
index 238222f..63dcc20 100644
--- a/src/m4.c
+++ b/src/m4.c
@@ -25,6 +25,7 @@
 #include <signal.h>
 #include <stdarg.h>
 
+#include "c-stack.h"
 #include "progname.h"
 #include "version-etc.h"
 
@@ -176,21 +177,6 @@ m4_warn (int errnum, const call_info *caller, const char 
*format, ...)
       va_end (args);
     }
 }
-
-#ifdef USE_STACKOVF
-
-/*---------------------------------------.
-| Tell user stack overflowed and abort.         |
-`---------------------------------------*/
-
-static void
-stackovf_handler (void)
-{
-  m4_error (EXIT_FAILURE, 0, NULL,
-           _("ERROR: stack overflow.  (Infinite define recursion?)"));
-}
-
-#endif /* USE_STACKOV */
 
 
 /*---------------------------------------------.
@@ -243,12 +229,12 @@ Preprocessor features:\n\
   -U, --undefine=NAME          undefine NAME\n\
 "), stdout);
       puts ("");
-      fputs (_("\
+      xprintf (_("\
 Limits control:\n\
   -G, --traditional            suppress all GNU extensions\n\
   -H, --hashsize=PRIME         set symbol lookup hash table size [509]\n\
-  -L, --nesting-limit=NUMBER   change artificial nesting limit [1024]\n\
-"), stdout);
+  -L, --nesting-limit=NUMBER   change nesting limit, 0 for unlimited [%d]\n\
+"), nesting_limit);
       puts ("");
       fputs (_("\
 Frozen state files:\n\
@@ -429,9 +415,8 @@ main (int argc, char *const *argv, char *const *envp)
   debug_init ();
   set_quoting_style (NULL, escape_quoting_style);
   set_char_quoting (NULL, ':', 1);
-#ifdef USE_STACKOVF
-  setup_stackovf_trap (argv, envp, stackovf_handler);
-#endif
+  if (c_stack_action (NULL) == 0)
+    nesting_limit = 0;
 
   /* First, we decode the arguments, to size up tables and stuff.  */
 
diff --git a/src/m4.h b/src/m4.h
index d16d87a..6290122 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -162,10 +162,6 @@ void m4_error (int, int, const call_info *, const char *, 
...)
   M4_GNUC_PRINTF (4, 5);
 void m4_warn (int, const call_info *, const char *, ...) M4_GNUC_PRINTF (3, 4);
 
-#ifdef USE_STACKOVF
-void setup_stackovf_trap (char *const *, char *const *,
-                         void (*handler) (void));
-#endif
 
 /* File: debug.c  --- debugging and tracing function.  */
 
diff --git a/src/stackovf.c b/src/stackovf.c
deleted file mode 100644
index 514e806..0000000
--- a/src/stackovf.c
+++ /dev/null
@@ -1,423 +0,0 @@
-/* Detect stack overflow (when getrlimit and sigaction or sigvec are available)
-
-   Copyright (C) 1993, 1994, 2006, 2007, 2008 Free Software
-   Foundation, Inc.
-   Jim Avera <address@hidden>, 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 <address@hidden> 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 <address@hidden> 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 <address@hidden> 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."  */
-
-#include "m4.h"                        /* stdlib.h, xmalloc() */
-
-#include <assert.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <signal.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);
-
-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)
-{
-  long diff;
-  diff = (p - stackend);
-
-#ifdef DEBUG_STKOVF
-  {
-    char buf[140];
-
-    snprintf (buf, sizeof buf,
-              "process_sigsegv: p=%#lx stackend=%#lx diff=%ld bot=%#lx\n",
-              (long) p, (long) stackend, (long) diff, (long) stackbot);
-    write (2, buf, strlen (buf));
-  }
-#endif
-
-  if (p != PARAM_NOSTACKOVF)
-    {
-      if ((long) sbrk (8192) == (long) -1)
-       {
-
-         /* sbrk failed.  Assume the RLIMIT_VMEM prevents expansion even
-            if the stack limit has not been reached.  */
-
-         write (2, "VMEM limit exceeded?\n", 21);
-         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;
-
-      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 can not 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
-
-    ss.ss_size = SIGSTKSZ;
-    ss.ss_sp = xmalloc ((unsigned) ss.ss_size);
-    ss.ss_flags = 0;
-    if (sigaltstack (&ss, NULL) < 0)
-      {
-       /* Oops - sigaltstack exists but doesn't work.  We can't
-          install the overflow detector, but should gracefully treat
-          it as though sigaltstack doesn't exist.  For example, this
-          happens when compiled with Linux 2.1 headers but run
-          against Linux 2.0 kernel.  */
-       free (ss.ss_sp);
-       if (errno == ENOSYS)
-         return;
-       error (EXIT_FAILURE, errno, "sigaltstack");
-      }
-  }
-
-#elif HAVE_SIGSTACK
-
-  {
-    struct sigstack ss;
-    void *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 */
-
-}
-- 
1.5.5.1


reply via email to

[Prev in Thread] Current Thread [Next in Thread]