m4-patches
[Top][All Lists]
Advanced

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

stackovf: optionally use libsigsegv


From: Eric Blake
Subject: stackovf: optionally use libsigsegv
Date: Thu, 17 Jul 2008 22:17:56 +0000 (UTC)
User-agent: Loom/3.14 (http://gmane.org/)

I'm committing this on the stackovf branch.  This completes the original goal I 
had when setting out to create the branch: stack overflow detection in m4 is no 
longer the unsafe portability nightmare it used to be.  If you install the 
optional library libsigsegv, this branch guarantees that on most modern porting 
targets, stack overflow no longer causes a core dump (cygwin, mingw) nor is an 
internal bug misdiagnosed as stack overflow (BSD, Linux, ...) (but we don't 
have any internal bugs, right?).  If you are lucky enough to have a platform 
that does this without libsigsegv (Solaris), more power to you.  Hopefully, 
with the recent email on the Austin Group list, I can convince the lkml mailing 
list that Linux is buggy for reporting the wrong uc_stack information on stack 
overflow

As with any good patch series, I enhanced the test suite; the file 
stackovf.test is cribbed from the master branch, but heavily tweaked to avoid 
perl, to obey modern portable shell practices (I hope), and to fit within the 
branch-1.6 non-Automake-based testsuite paradigm.

I also revived the DEBUG_STKOVF macro, which was deleted earlier in the branch, 
such that I can build a debug version and intentionally crash m4 by exporting 
M4_CRASH in the environment.

Next step - figure out how to make the master branch have two simultaneous 
gnulib checkouts (the c-stack, strsignal, and related modules are not needed 
for libm4.a, just the final m4 executable).  Then I can merge this into both 
branch-1.6 and master.

From: Eric Blake <address@hidden>
Date: Thu, 17 Jul 2008 12:00:49 -0600
Subject: [PATCH] Adjust to c-stack changes in gnulib.

* src/Makefile.am (m4_LDADD): Use libsigsegv when available and
necessary, via LIBCSTACK.
* src/m4.c (main) [DEBUG_STACKOVF]: Make it easier to test fault
handlers.
* checks/stackovf.test: New file.
* checks/Makefile.in (CHECKS): Add stackovf.test, and factor...
(DOC_CHECKS): ...generated documentation tests into new macro.
(DISTFILES): Distribute stackovf.test.
* checks/check-them: Special-case stackovf.test.
* NEWS: Enhance the NEWS item for -L improvements.
* README: Mention the optional dependency.
* HACKING: Mention maintenance burden added by libsigsegv.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog            |   16 ++++++++
 HACKING              |    7 ++++
 NEWS                 |    7 +++-
 README               |    9 +++++
 checks/Makefile.in   |   12 ++++---
 checks/check-them    |   12 ++++++
 checks/stackovf.test |   99 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/Makefile.am      |    2 +-
 src/m4.c             |   16 ++++++++
 9 files changed, 173 insertions(+), 7 deletions(-)
 create mode 100755 checks/stackovf.test

diff --git a/ChangeLog b/ChangeLog
index c51d171..e182a2b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2008-07-17  Eric Blake  <address@hidden>
+
+       Adjust to c-stack changes in gnulib.
+       * src/Makefile.am (m4_LDADD): Use libsigsegv when available and
+       necessary, via LIBCSTACK.
+       * src/m4.c (main) [DEBUG_STACKOVF]: Make it easier to test fault
+       handlers.
+       * checks/stackovf.test: New file.
+       * checks/Makefile.in (CHECKS): Add stackovf.test, and factor...
+       (DOC_CHECKS): ...generated documentation tests into new macro.
+       (DISTFILES): Distribute stackovf.test.
+       * checks/check-them: Special-case stackovf.test.
+       * NEWS: Enhance the NEWS item for -L improvements.
+       * README: Mention the optional dependency.
+       * HACKING: Mention maintenance burden added by libsigsegv.
+
 2008-06-23  Eric Blake  <address@hidden>
 
        Adjust to new gnulib-tool layout.
diff --git a/HACKING b/HACKING
index fd8cd1e..e127494 100644
--- a/HACKING
+++ b/HACKING
@@ -62,6 +62,13 @@ and is not part of a release distribution.
   Note that none of these bootstrapping dependencies should be required
   by a distributed release.
 
+* M4 has an optional build dependency.  In order to ensure that the
+  dependency remains optional, you can avoid the library by using
+  `./configure --without-libsigsegv-prefix'.  In order to ensure that
+  the dependency is still viable with the current code base, you should
+  install:
+  - Libsigsegv 2.5 or later
+
 * Either add the gnulib directory to your PATH, or run
     GNULIB_TOOL=path/to/gnulib/gnulib-tool ./bootstrap
 
diff --git a/NEWS b/NEWS
index 5aae856..bfda4d4 100644
--- a/NEWS
+++ b/NEWS
@@ -38,7 +38,12 @@ Foundation, Inc.
      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.
+   unlimited on platforms that can detect and deal with stack overflow.  On
+   systems that lack alternate stack support, such as Cygwin, and on
+   systems that do not obey the POSIX semantics for distinguishing stack
+   overflow from other exceptions, such as Linux, you can optionally
+   install the libsigsegv library to enhance m4's ability to accurately
+   report stack overflow: http://www.gnu.org/software/libsigsegv/
 
 ** The `defn' builtin now warns when operating on an undefined macro name.
    To simulate 1.4.x behavior, use:
diff --git a/README b/README
index 548ffb9..ea5061f 100644
--- a/README
+++ b/README
@@ -19,6 +19,15 @@ ahead and start with `./configure'.  If you are trying to 
build `m4'
 from git or CVS, more information can be found in the file HACKING,
 only found in a version control checkout.
 
+M4 has an optional dependency on the libsigsegv library:
+  http://www.gnu.org/software/libsigsegv/
+If the library has not been installed in the standard location, you
+can use `./configure --with-libsigsegv-prefix=/path/to/dir', to make
+the build of `m4' use /path/to/dir/include/sigsegv.h as appropriate.
+The use of this library is optional; the only difference in having it
+available is that it increases the number of platforms where `m4' can
+correctly distinguish stack overflow from an internal bug.
+
 In the subdirectory `examples' you will find various m4 files, ranging
 from trivial test files to rather advanced macros.  If you intend to
 use m4 seriously, you might find useful material down there.
diff --git a/checks/Makefile.in b/checks/Makefile.in
index 0e1091e..c43c2cc 100644
--- a/checks/Makefile.in
+++ b/checks/Makefile.in
@@ -36,14 +36,16 @@ program_transform_name = @program_transform_name@
 AWK = @AWK@
 
 # Vern says that the first star is required around an Alpha make bug.
-CHECKS = $(srcdir)/*[0-9][0-9][0-9].*
+DOC_CHECKS = $(srcdir)/*[0-9][0-9][0-9].*
+CHECKS = $(DOC_CHECKS) $(srcdir)/stackovf.test
 # Makefile.in is automatically distributed by automake.
-DISTFILES = $(srcdir)/get-them $(srcdir)/check-them $(srcdir)/stamp-checks
+DISTFILES = $(srcdir)/get-them $(srcdir)/check-them $(srcdir)/stamp-checks \
+       $(srcdir)/stackovf.test
 
 all: $(srcdir)/stamp-checks
 
 $(srcdir)/stamp-checks: $(srcdir)/get-them $(srcdir)/../doc/m4.texinfo
-       rm -f $(CHECKS)
+       rm -f $(DOC_CHECKS)
        cd $(srcdir) && AWK=$(AWK) ./get-them ../doc/m4.texinfo
        touch $(srcdir)/stamp-checks
 
@@ -73,13 +75,13 @@ distclean: clean
        rm -f Makefile
 
 maintainer-clean realclean: distclean
-       rm -f $(CHECKS) $(srcdir)/stamp-checks
+       rm -f $(DOC_CHECKS) $(srcdir)/stamp-checks
 
 distdir: dist
 
 dist: $(DISTFILES)
        @echo "Copying distribution files"
-       @for file in $(DISTFILES) $(CHECKS); do \
+       @for file in $(DISTFILES) $(DOC_CHECKS); do \
          ln $$file ../$(PACKAGE)-$(VERSION)/checks 2> /dev/null \
            || cp -p $$file ../$(PACKAGE)-$(VERSION)/checks; \
        done
diff --git a/checks/check-them b/checks/check-them
index 7fba1d6..f66322b 100755
--- a/checks/check-them
+++ b/checks/check-them
@@ -70,6 +70,18 @@ do
     continue
   }
   echo "Checking $file"
+
+  case $file in
+    *stackovf.test)
+      "$file" "$m4"
+      case $? in
+       77) skipped="$skipped $file";;
+       0) ;;
+       *) failed="$failed $file"
+      esac
+      continue ;;
+  esac
+
   options=`sed -ne '3s/^dnl @ extra options: //p;3q' "$file"`
   sed -e '/^dnl @/d' -e '/^\^D$/q' "$file" \
     | LC_MESSAGES=C M4PATH=$examples "$m4" -d $options - >$out 2>$err
diff --git a/checks/stackovf.test b/checks/stackovf.test
new file mode 100755
index 0000000..78c3340
--- /dev/null
+++ b/checks/stackovf.test
@@ -0,0 +1,99 @@
+#!/bin/sh
+# This file is part of the GNU m4 testsuite
+# Copyright (C) 2000, 2003, 2007, 2008 Free Software Foundation, Inc.
+#
+# 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/>.
+
+# Script to verify that stack overflow is diagnosed properly when
+# there is infinite macro call nesting, provided the OS supports it.
+
+m4="$1"
+
+# Skip this test if -L defaults to 1024 instead of 0, as that is our
+# indicator that the OS does not support stack overflow detection.
+("$m4" --help | grep 'nesting.*\[0\]') >/dev/null 2>&1 \
+  || {
+       echo "$0: skipping test, no stack overflow support detected in $m4"
+       exit 77
+     }
+
+# On some systems the ulimit command is available in ksh or bash but not sh
+(exec 2>/dev/null; ulimit -Ss 300) || {
+  for altshell in bash bsh ksh zsh ; do
+    if (exec >/dev/null 2>&1; $altshell -c 'ulimit -Ss 300') && test -z "$2"
+    then
+      echo "Using $altshell because it supports ulimit"
+      exec $altshell "$0" "$@" running-with-$altshell
+      exit 1
+    fi
+  done
+}
+
+tmpdir=
+trap 'st=$?; rm -rf "$tmpdir" && exit $st' 0
+trap '(exit $?); exit $?' 1 2 3 15
+
+# Create a temporary subdirectory $tmpdir in $TMPDIR (default /tmp).
+# Use mktemp if possible; otherwise fall back on mkdir,
+# with $RANDOM to make collisions less likely.
+: ${TMPDIR=/tmp}
+{
+  tmpdir=`
+    (umask 077 && mktemp -d "$TMPDIR/m4stk-XXXXXX") 2>/dev/null
+  ` &&
+  test -n "$tmpdir" && test -d "$tmpdir"
+} || {
+  tmpdir=$TMPDIR/m4stk-$$-$RANDOM
+  (umask 077 && mkdir "$tmpdir")
+} || exit $?
+tmpfile="$tmpdir"/m4.out
+
+# Limit the stack size if the shell we are running permits it
+if (exec 2>/dev/null; ulimit -Ss 50)
+then
+  ulimit -Ss 50
+  echo "Stack soft limit set to `ulimit -s`K";
+else
+  echo "Can't reset stack limit - this may take a while..."
+fi
+
+# Induce stack overflow.
+echo 'define(a,a(a))a' | "$m4" > "$tmpfile" 2>&1
+result=$?
+
+exitcode=1
+if test $result -eq 0 ; then
+  echo "Failure - $m4 did not abort"
+else
+  # See if stack overflow was diagnosed.
+  case `cat "$tmpfile"` in
+    *stack\ overflow*)
+      case `echo "$tmpdir"/*` in
+       $tmpfile)
+          echo "Pass"
+          exitcode=0 ;;
+       *) echo "Failure - $m4 created unexpected core dump"
+          ls -l "$tmpdir" ;;
+      esac ;;
+    *) echo "Failure - $m4 aborted unexpectedly";
+       ;;
+    esac
+fi
+
+test $exitcode = 0 ||
+    { echo "Output from $m4:"; cat $tmpfile; }
+
+exit $exitcode
diff --git a/src/Makefile.am b/src/Makefile.am
index 900f8ea..80b9acf 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -24,4 +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
-m4_LDADD = ../lib/libm4.a $(LIBM4_LIBDEPS) $(POW_LIB)
+m4_LDADD = ../lib/libm4.a $(LIBM4_LIBDEPS) $(POW_LIB) $(LIBCSTACK)
diff --git a/src/m4.c b/src/m4.c
index 970aa8b..a24f82d 100644
--- a/src/m4.c
+++ b/src/m4.c
@@ -488,6 +488,22 @@ main (int argc, char *const *argv, char *const *envp)
   sigaction (SIGFPE, &act, NULL);
   sigaction (SIGBUS, &act, NULL);
 
+#ifdef DEBUG_STKOVF
+  /* Make it easier to test our fault handlers.  Exporting M4_CRASH=0
+     attempts a SIGSEGV, exporting it as 1 attempts an assertion
+     failure with a fallback to abort.  */
+  {
+    char *crash = getenv ("M4_CRASH");
+    if (crash)
+      {
+        if (!atoi (crash))
+          ++*(int *) 8;
+        assert (false);
+        abort ();
+      }
+  }
+#endif /* DEBUG_STKOVF */
+
   /* First, we decode the arguments, to size up tables and stuff.  */
   head = tail = NULL;
 
-- 
1.5.6







reply via email to

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