bug-gnulib
[Top][All Lists]
Advanced

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

c-stack: use libsigsegv when possible


From: Eric Blake
Subject: c-stack: use libsigsegv when possible
Date: Wed, 16 Jul 2008 07:08:53 -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

Is this patch okay to apply?  So far, I've tested it on:

cygwin with libsigsegv
mingw without libsigsegv
mingw with libsigsegv
Linux without libsigsegv
Linux with libsigsegv

When compiling for platforms like Solaris where c-stack has determined
HAVE_XSI_STACK_OVERFLOW_HEURISTIC, the use of libsigsegv just bloats the
application, since c-stack was already sufficient.  However, most
platforms benefit from libsigsegv, either because it avoids false
positives (Linux, BSD, ...) or because it is the only way to execute code
after stack overflow (cygwin, mingw).  Should I also add lib-ignore to the
dependencies of c-stack, so that Solaris need not waste space if
libsigsegv is not used independently of c-stack?

In writing the patch, I noticed that it is probably not portable to
longjmp out of a stack overflow handler - POSIX is explicit that longjmp
is not async-signal safe, because the stack overflow might have occurred
in the middle of a library function like malloc; even though you can
manage to get back to the original stack, you no longer have guarantees
that malloc will work.  So, we either need to document this in the
contract of c_stack_action, or we need to add a function in c-stack.h that
the user must call before attempting longjmp anyway; this wrapper would be
responsible for calling libsigsegv's sigsegv_leave_handler as needed.
Preferences?

- --
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

iEYEARECAAYFAkh98uUACgkQ84KuGfSFAYBtOgCg1OBDKOqzri97ozEmzAi+D9BH
R6QAoLhMG+7wfZKaaulfCE/TDZGaqlLN
=CtWz
-----END PGP SIGNATURE-----
>From 50c0b0bb5b6ab94e422c0a6ab40a570d92d69444 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Wed, 16 Jul 2008 06:22:54 -0600
Subject: [PATCH] Make c-stack use libsigsegv, when available.

* modules/c-stack (Depends-on): Add libsigsegv.
* modules/c-stack-tests (Makefile.am): Link with libsigsegv, if
needed.
* lib/c-stack.c (SIGSTKSZ): Define fallback.
(segv_handler, c_stack_action)
[HAVE_LIBSIGSEGV && !HAVE_XSI_STACK_OVERFLOW_HEURISTIC]: Add new
implementation when libsigsegv is available, but only when using
the library is necessary.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog             |   12 ++++++
 lib/c-stack.c         |  105 +++++++++++++++++++++++++++++++++++++++---------
 modules/c-stack       |    1 +
 modules/c-stack-tests |    2 +-
 4 files changed, 99 insertions(+), 21 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 91c45ce..a25348b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2008-07-16  Eric Blake  <address@hidden>
+
+       Make c-stack use libsigsegv, when available.
+       * modules/c-stack (Depends-on): Add libsigsegv.
+       * modules/c-stack-tests (Makefile.am): Link with libsigsegv, if
+       needed.
+       * lib/c-stack.c (SIGSTKSZ): Define fallback.
+       (segv_handler, c_stack_action)
+       [HAVE_LIBSIGSEGV && !HAVE_XSI_STACK_OVERFLOW_HEURISTIC]: Add new
+       implementation when libsigsegv is available, but only when using
+       the library is necessary.
+
 2008-07-14  Bruno Haible  <address@hidden>
 
        * m4/libsigsegv.m4: Remove unneeded AC_PREREQ.
diff --git a/lib/c-stack.c b/lib/c-stack.c
index 96bd2bf..e0bb3ae 100644
--- a/lib/c-stack.c
+++ b/lib/c-stack.c
@@ -53,6 +53,9 @@
 #if ! HAVE_STACK_T && ! defined stack_t
 typedef struct sigaltstack stack_t;
 #endif
+#ifndef SIGSTKSZ
+# define SIGSTKSZ 16384
+#endif
 
 #include <stdlib.h>
 #include <string.h>
@@ -68,6 +71,10 @@ typedef struct sigaltstack stack_t;
 # define STDERR_FILENO 2
 #endif
 
+#if HAVE_LIBSIGSEGV
+# include <sigsegv.h>
+#endif
+
 #include "c-stack.h"
 #include "exitfail.h"
 
@@ -110,7 +117,83 @@ die (int signo)
   abort ();
 }
 
-#if HAVE_SIGALTSTACK && HAVE_DECL_SIGALTSTACK
+#if (HAVE_SIGALTSTACK && HAVE_DECL_SIGALTSTACK) || HAVE_LIBSIGSEGV
+
+/* Storage for the alternate signal stack.  */
+static union
+{
+  char buffer[SIGSTKSZ];
+
+  /* These other members are for proper alignment.  There's no
+     standard way to guarantee stack alignment, but this seems enough
+     in practice.  */
+  long double ld;
+  long l;
+  void *p;
+} alternate_signal_stack;
+
+static void
+null_action (int signo __attribute__ ((unused)))
+{
+}
+
+#endif /* SIGALTSTACK || LIBSIGSEGV */
+
+/* Only use libsigsegv if we need it; platforms like Solaris can
+   detect stack overflow without the overhead of an external
+   library.  */
+#if HAVE_LIBSIGSEGV && ! HAVE_XSI_STACK_OVERFLOW_HEURISTIC
+
+/* Handle a segmentation violation and exit.  This function is
+   async-signal-safe.  */
+
+static void segv_handler (int, stackoverflow_context_t) 
__attribute__((noreturn));
+static void
+segv_handler (int emergency,
+              stackoverflow_context_t context __attribute__ ((unused)))
+{
+# if DEBUG
+  {
+    char buf[1024];
+    sprintf (buf, "segv_handler emergency=%d\n", emergency);
+    write (STDERR_FILENO, buf, strlen (buf));
+  }
+# endif
+
+  die (emergency ? SIGSEGV : 0);
+}
+
+/* Set up ACTION so that it is invoked on C stack overflow.  Return -1
+   (setting errno) if this cannot be done.
+
+   When ACTION is called, it is passed an argument equal to SIGSEGV
+   for a segmentation violation that does not appear related to stack
+   overflow, and is passed zero otherwise.  On many platforms it is
+   hard to tell; when in doubt, zero is passed.
+
+   A null ACTION acts like an action that does nothing.
+
+   ACTION must be async-signal-safe.  ACTION together with its callees
+   must not require more than SIGSTKSZ bytes of stack space.  */
+
+int
+c_stack_action (void (*action) (int))
+{
+  segv_action = action ? action : null_action;
+  program_error_message = _("program error");
+  stack_overflow_message = _("stack overflow");
+
+  if (stackoverflow_install_handler (segv_handler,
+                                     alternate_signal_stack.buffer,
+                                     sizeof alternate_signal_stack.buffer))
+    {
+      errno = ENOTSUP;
+      return -1;
+    }
+  return 0;
+}
+
+#elif HAVE_SIGALTSTACK && HAVE_DECL_SIGALTSTACK
 
 /* Direction of the C runtime stack.  This function is
    async-signal-safe.  */
@@ -126,19 +209,6 @@ find_stack_direction (char const *addr)
 }
 # endif
 
-/* Storage for the alternate signal stack.  */
-static union
-{
-  char buffer[SIGSTKSZ];
-
-  /* These other members are for proper alignment.  There's no
-     standard way to guarantee stack alignment, but this seems enough
-     in practice.  */
-  long double ld;
-  long l;
-  void *p;
-} alternate_signal_stack;
-
 # if SIGACTION_WORKS
 
 /* Handle a segmentation violation and exit.  This function is
@@ -189,11 +259,6 @@ segv_handler (int signo, siginfo_t *info,
 }
 # endif
 
-static void
-null_action (int signo __attribute__ ((unused)))
-{
-}
-
 /* Set up ACTION so that it is invoked on C stack overflow.  Return -1
    (setting errno) if this cannot be done.
 
@@ -240,7 +305,7 @@ c_stack_action (void (*action) (int))
   return sigaction (SIGSEGV, &act, NULL);
 }
 
-#else /* ! (HAVE_SIGALTSTACK && HAVE_DECL_SIGALTSTACK) */
+#else /* ! ((HAVE_SIGALTSTACK && HAVE_DECL_SIGALTSTACK) || HAVE_LIBSIGSEGV) */
 
 int
 c_stack_action (void (*action) (int)  __attribute__ ((unused)))
diff --git a/modules/c-stack b/modules/c-stack
index d3e7e09..93eef29 100644
--- a/modules/c-stack
+++ b/modules/c-stack
@@ -12,6 +12,7 @@ exitfail
 unistd
 raise
 sigaction
+libsigsegv
 
 configure.ac:
 gl_C_STACK
diff --git a/modules/c-stack-tests b/modules/c-stack-tests
index 291f58d..a520e57 100644
--- a/modules/c-stack-tests
+++ b/modules/c-stack-tests
@@ -11,5 +11,5 @@ Makefile.am:
 TESTS += test-c-stack.sh
 TESTS_ENVIRONMENT += EXEEXT='@EXEEXT@'
 check_PROGRAMS += test-c-stack
-test_c_stack_LDADD = $(LDADD) @LIBINTL@
+test_c_stack_LDADD = $(LDADD) $(LIBSIGSEGV) @LIBINTL@
 MOSTLYCLEANFILES += t-c-stack.tmp
-- 
1.5.6


reply via email to

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