-----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 [EMAIL PROTECTED] -----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 <[EMAIL PROTECTED]> 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 <[EMAIL PROTECTED]> --- 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 <[EMAIL PROTECTED]> + + 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 <[EMAIL PROTECTED]> * 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