bug-gnulib
[Top][All Lists]
Advanced

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

Re: undefined behavior in closeout, aggravated by libsigsegv


From: Eric Blake
Subject: Re: undefined behavior in closeout, aggravated by libsigsegv
Date: Wed, 22 Jul 2009 22:09:14 -0600
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.22) Gecko/20090605 Thunderbird/2.0.0.22 Mnenhy/0.7.6.666

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

According to Bruno Haible on 7/18/2009 1:03 AM:
>> there is currently a 
>> thread on the cygwin list about a crash under Windows 2008 R2 64-bit, where 
>> Windows has tightened the rules on what forms a valid SEH exception chain 
>> and 
>> the cygwin handler was violating those rules; and that thread has also 
>> raised 
>> the concern that libsigsegv may be making the same mistakes by trying to 
>> override cygwin's handler:
> 
> The mail at http://cygwin.com/ml/cygwin/2009-07/msg00607.html indicates that
> the problem was with incorrect nesting of SEH exception chain 
> additions/removals.
> The values of the addresses in that chain appear to be irrelevant. Thus it
> does not matter whether libsigsegv is compiled as a DLL or statically. At 
> least
> that's what I understand from the thread.

Actually, the bug is that libsigsegv is too eager to claim that an SEH
exception is a SEGV, even if cygwin was otherwise prepared to handle it
and not raise SIGSEGV.  The fix is to delay handling of the fault until
after the SIGSEGV has actually been raised, although for cygwin 1.5, the
SEH handler is still needed to learn the faulting address since it wasn't
until today's patch to cygwin 1.7 that si_addr was populated correctly.

Here's three patches that add test cases, then respectively fixes cygwin
1.7 and 1.5 to pass the new tests.  I've also tested that on platforms
like Linux that the new tests pass, as well as testing that mingw skips
the tests but otherwise still compiles fine.

$ git pull git://repo.or.cz/libsigsegv/ericb.git master

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

iEYEARECAAYFAkpn4moACgkQ84KuGfSFAYCfJQCfYbPJk2csPQu18zqEyCItb4YV
Sa8AoNStSmbs995mK51Vp1wMivy1x8sy
=H36q
-----END PGP SIGNATURE-----
>From 8a62e3538cad933a1421578499d6ce170dd035a6 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Wed, 22 Jul 2009 13:36:17 -0600
Subject: [PATCH 1/3] Detect library bug when used on cygwin.

* m4/efault.m4 (SV_EFAULT): New file.
* tests/efault1.c: Likewise.
* tests/efault2.c: Likewise.
* tests/efault3.c: Likewise.
* tests/Makefile.am (TESTS, noinst_PROGRAMS): Build new tests.
* configure.ac (SV_EFAULT): Invoke new macro.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog         |   10 ++++++
 configure.ac      |    3 ++
 m4/efault.m4      |   27 +++++++++++++++
 tests/Makefile.am |    2 +
 tests/efault1.c   |   72 +++++++++++++++++++++++++++++++++++++++++
 tests/efault2.c   |   81 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/efault3.c   |   92 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 287 insertions(+), 0 deletions(-)
 create mode 100644 m4/efault.m4
 create mode 100644 tests/efault1.c
 create mode 100644 tests/efault2.c
 create mode 100644 tests/efault3.c

diff --git a/ChangeLog b/ChangeLog
index c2fa127..d0a69e0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2009-07-22  Eric Blake  <address@hidden>
+
+       Detect library bug when used on cygwin.
+       * m4/efault.m4 (SV_EFAULT): New file.
+       * tests/efault1.c: Likewise.
+       * tests/efault2.c: Likewise.
+       * tests/efault3.c: Likewise.
+       * tests/Makefile.am (TESTS, noinst_PROGRAMS): Build new tests.
+       * configure.ac (SV_EFAULT): Invoke new macro.
+
 2009-06-23  Bruno Haible  <address@hidden>

        * Makefile.am (check-next): No longer ask for copies of config.log.
diff --git a/configure.ac b/configure.ac
index 2a54c96..1393642 100644
--- a/configure.ac
+++ b/configure.ac
@@ -896,6 +896,9 @@ AC_DEFINE_UNQUOTED([CFG_HANDLER], ["$CFG_HANDLER"],
   [The name of the file implementing the handler functionality.])
 AC_SUBST([CFG_HANDLER])

+dnl Learn whether we can test for EFAULT handling.
+SV_EFAULT
+
 { echo; echo "${term_bold}Build Parameters:${term_norm}"; } >& AS_MESSAGE_FD

 dnl Relocatability is a nop for this package.
diff --git a/m4/efault.m4 b/m4/efault.m4
new file mode 100644
index 0000000..d846a48
--- /dev/null
+++ b/m4/efault.m4
@@ -0,0 +1,27 @@
+# efault.m4 serial 1 (libsigsegv-2.7)
+dnl Copyright (C) 2009 Eric Blake <address@hidden>
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License.  As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+dnl Determine whether the OS catches some mistakes with EFAULT, to ensure
+dnl that libsigsegv does not interfere with EFAULT handling.
+AC_DEFUN([SV_EFAULT], [
+  AC_CACHE_CHECK([whether EFAULT is supported], [sv_cv_efault_supported], [
+    AC_RUN_IFELSE([
+      AC_LANG_PROGRAM([[
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+]], [return !(open (NULL, O_RDONLY) == -1 && errno == EFAULT);])],
+      [sv_cv_efault_supported=yes],
+      [sv_cv_efault_supported=no],
+      [sv_cv_efault_supported="guessing no"])
+  ])
+  if test "$sv_cv_efault_supported" = yes; then
+    AC_DEFINE([HAVE_EFAULT_SUPPORT], [1], [Define to 1 if syscalls detect bad
+pointers with EFAULT.])
+  fi
+])
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 45615fe..5e31427 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -21,6 +21,7 @@
 AUTOMAKE_OPTIONS = 1.11 gnits no-dependencies color-tests

 TESTS = sigsegv1 sigsegv2 sigsegv3 stackoverflow1 stackoverflow2
+TESTS += efault1 efault2 efault3

 EXTRA_DIST = mmaputil.h

@@ -28,6 +29,7 @@ INCLUDES = -I../src
 DEFS = @DEFS@
 LDADD = ../src/libsigsegv.la
 noinst_PROGRAMS = sigsegv1 sigsegv2 sigsegv3 stackoverflow1 stackoverflow2
+noinst_PROGRAMS += efault1 efault2 efault3

 # The following rule is necessary to avoid a toplevel "make -n" failure.
 ../src/libsigsegv.la :
diff --git a/tests/efault1.c b/tests/efault1.c
new file mode 100644
index 0000000..f491d92
--- /dev/null
+++ b/tests/efault1.c
@@ -0,0 +1,72 @@
+/* Test that libsigsegv does not interfere with EFAULT handling.
+   Copyright (C) 2009  Eric Blake <address@hidden>
+
+   This program 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 2, or (at your option)
+   any later version.
+
+   This program 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, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#ifndef _MSC_VER
+# include <config.h>
+#endif
+
+#include "sigsegv.h"
+
+#if HAVE_SIGSEGV_RECOVERY && HAVE_EFAULT_SUPPORT
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static int
+handler (void *fault_address, int serious)
+{
+  abort ();
+}
+
+int
+main ()
+{
+  /* Test whether the OS handles some faults by itself.  */
+  if (open (NULL, O_RDONLY) != -1 || errno != EFAULT)
+    {
+      fprintf (stderr, "EFAULT not detected alone.\n");
+      exit (1);
+    }
+
+  /* Install the SIGSEGV handler.  */
+  if (sigsegv_install_handler (&handler) < 0)
+    exit (2);
+
+  /* Test that the library does not interfere with OS faults.  */
+  if (open (NULL, O_RDONLY) != -1 || errno != EFAULT)
+    {
+      fprintf (stderr, "EFAULT not detected with handler.\n");
+      exit (1);
+    }
+
+  /* Test passed!  */
+  printf ("Test passed.\n");
+  return 0;
+}
+
+#else
+
+int
+main ()
+{
+  return 77;
+}
+
+#endif
diff --git a/tests/efault2.c b/tests/efault2.c
new file mode 100644
index 0000000..0d7cd68
--- /dev/null
+++ b/tests/efault2.c
@@ -0,0 +1,81 @@
+/* Test that libsigsegv does not interfere with EFAULT handling.
+   Copyright (C) 2009  Eric Blake <address@hidden>
+
+   This program 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 2, or (at your option)
+   any later version.
+
+   This program 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, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#ifndef _MSC_VER
+# include <config.h>
+#endif
+
+#include "sigsegv.h"
+
+#if HAVE_STACK_OVERFLOW_RECOVERY && HAVE_EFAULT_SUPPORT
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifndef SIGSTKSZ
+# define SIGSTKSZ 16384
+#endif
+
+static void
+handler (int emergency, stackoverflow_context_t scp)
+{
+  abort ();
+}
+
+int
+main ()
+{
+  /* glibc says: Users should use SIGSTKSZ as the size of user-supplied
+     buffers.  */
+  char mystack[SIGSTKSZ];
+
+  /* Test whether the OS handles some faults by itself.  */
+  if (open (NULL, O_RDONLY) != -1 || errno != EFAULT)
+    {
+      fprintf (stderr, "EFAULT not detected alone.\n");
+      exit (1);
+    }
+
+  /* Install the stack overflow handler.  */
+  if (stackoverflow_install_handler (&handler, mystack, sizeof (mystack))
+      < 0)
+    exit (2);
+
+  /* Test that the library does not interfere with OS faults.  */
+  if (open (NULL, O_RDONLY) != -1 || errno != EFAULT)
+    {
+      fprintf (stderr, "EFAULT not detected with handler.\n");
+      exit (1);
+    }
+
+  /* Test passed!  */
+  printf ("Test passed.\n");
+  return 0;
+}
+
+#else
+
+int
+main ()
+{
+  return 77;
+}
+
+#endif
diff --git a/tests/efault3.c b/tests/efault3.c
new file mode 100644
index 0000000..9ebec26
--- /dev/null
+++ b/tests/efault3.c
@@ -0,0 +1,92 @@
+/* Test that libsigsegv does not interfere with EFAULT handling.
+   Copyright (C) 2009  Eric Blake <address@hidden>
+
+   This program 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 2, or (at your option)
+   any later version.
+
+   This program 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, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+#ifndef _MSC_VER
+# include <config.h>
+#endif
+
+#include "sigsegv.h"
+
+#if HAVE_STACK_OVERFLOW_RECOVERY && HAVE_SIGSEGV_RECOVERY && 
HAVE_EFAULT_SUPPORT
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifndef SIGSTKSZ
+# define SIGSTKSZ 16384
+#endif
+
+static int
+sigsegv_handler (void *fault_address, int serious)
+{
+  abort ();
+}
+
+static void
+stackoverflow_handler (int emergency, stackoverflow_context_t scp)
+{
+  abort ();
+}
+
+int
+main ()
+{
+  /* glibc says: Users should use SIGSTKSZ as the size of user-supplied
+     buffers.  */
+  char mystack[SIGSTKSZ];
+
+  /* Test whether the OS handles some faults by itself.  */
+  if (open (NULL, O_RDONLY) != -1 || errno != EFAULT)
+    {
+      fprintf (stderr, "EFAULT not detected alone.\n");
+      exit (1);
+    }
+
+  /* Install the stack overflow handler.  */
+  if (stackoverflow_install_handler (&stackoverflow_handler,
+                                     mystack, sizeof (mystack))
+      < 0)
+    exit (2);
+
+  /* Install the SIGSEGV handler.  */
+  if (sigsegv_install_handler (&sigsegv_handler) < 0)
+    exit (2);
+
+  /* Test that the library does not interfere with OS faults.  */
+  if (open (NULL, O_RDONLY) != -1 || errno != EFAULT)
+    {
+      fprintf (stderr, "EFAULT not detected with handler.\n");
+      exit (1);
+    }
+
+  /* Test passed!  */
+  printf ("Test passed.\n");
+  return 0;
+}
+
+#else
+
+int
+main ()
+{
+  return 77;
+}
+
+#endif
-- 
1.6.3.3.334.g916e1


>From 6c53cd7aa11b27eb93526fc99bfe94ca5d81ae54 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Wed, 22 Jul 2009 15:46:44 -0600
Subject: [PATCH 2/3] Fix interaction with cygwin 1.7.

* src/handler-win32.c (main_exception_filter): Don't handle normal
segv here.
(user_handler, sigsegv_install_handler, sigsegv_deinstall_handler)
(sigsegv_leave_handler): Use the Unix implementation instead.
* NEWS: Document this.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog           |    7 +++++++
 NEWS                |    1 +
 src/handler-win32.c |   39 +++++++++++++++++++++++++++++++++++----
 3 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index d0a69e0..27ff60a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2009-07-22  Eric Blake  <address@hidden>

+       Fix interaction with cygwin 1.7.
+       * src/handler-win32.c (main_exception_filter): Don't handle normal
+       segv here.
+       (user_handler, sigsegv_install_handler, sigsegv_deinstall_handler)
+       (sigsegv_leave_handler): Use the Unix implementation instead.
+       * NEWS: Document this.
+
        Detect library bug when used on cygwin.
        * m4/efault.m4 (SV_EFAULT): New file.
        * tests/efault1.c: Likewise.
diff --git a/NEWS b/NEWS
index 90a95b2..6e6669b 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,7 @@ New in 2.7:
 * Support for platforms that follow POSIX:2008, not POSIX:2001.
 * Support for MirBSD 10.
 * Support for IRIX 5.3. Contributed by Eric Blake.
+* Improved support for Cygwin 1.7. Contributed by Eric Blake.

 New in 2.6:

diff --git a/src/handler-win32.c b/src/handler-win32.c
index 479bd03..a48ad8f 100644
--- a/src/handler-win32.c
+++ b/src/handler-win32.c
@@ -1,5 +1,5 @@
 /* Fault handler information.  Woe32 version.
-   Copyright (C) 1993-1999, 2002-2003, 2007-2008  Bruno Haible <address@hidden>
+   Copyright (C) 1993-1999, 2002-2003, 2007-2009  Bruno Haible <address@hidden>
    Copyright (C) 2003  Paolo Bonzini <address@hidden>

    This program is free software; you can redistribute it and/or modify
@@ -28,8 +28,33 @@
  * extern DWORD GetLastError (void);
  */

+#ifndef __attribute__
+# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8)
+#  define __attribute__(x)
+# endif
+#endif
+#define UNUSED __attribute__ ((__unused__))
+
+#ifdef __CYGWIN__
+
+/* Cygwin expects to handle some faults itself in order to implement
+   EFAULT returns from syscalls (not all faults are SIGSEGV), so we
+   must not interfere with that mechanism; using Unix handling is the
+   best approach.  But cygwin lacks sigaltstack, and thus we must use
+   win32 handling for stack overflow.  */
+
+# undef HAVE_STACK_OVERFLOW_RECOVERY
+# define HAVE_STACK_OVERFLOW_RECOVERY 0
+# define stackoverflow_install_handler stackoverflow_install_handler_dummy
+# define stackoverflow_deinstall_handler stackoverflow_deinstall_handler_dummy
+# include "handler-unix.c"
+# undef stackoverflow_install_handler
+# undef stackoverflow_deinstall_handler
+
+#else
 /* User's SIGSEGV handler.  */
 static sigsegv_handler_t user_handler = (sigsegv_handler_t) NULL;
+#endif

 /* Stack overflow handling is tricky:
    First, we must catch a STATUS_STACK_OVERFLOW exception. This is signalled
@@ -123,10 +148,12 @@ main_exception_filter (EXCEPTION_POINTERS *ExceptionInfo)
   if ((stk_user_handler
        && ExceptionInfo->ExceptionRecord->ExceptionCode == 
STATUS_STACK_OVERFLOW
       )
+#ifndef __CYGWIN__
       ||
       (user_handler != (sigsegv_handler_t)NULL
-       && ExceptionInfo->ExceptionRecord->ExceptionCode == 
EXCEPTION_ACCESS_VIOLATION
-     ))
+       && ExceptionInfo->ExceptionRecord->ExceptionCode == 
EXCEPTION_ACCESS_VIOLATION)
+#endif
+      )
     {
 #if 0 /* for debugging only */
       printf ("Exception!\n");
@@ -182,6 +209,7 @@ main_exception_filter (EXCEPTION_POINTERS *ExceptionInfo)
               *(unsigned long *)(new_safe_esp + 8) = (unsigned long) 
safe_context;
               return EXCEPTION_CONTINUE_EXECUTION;
             }
+#ifndef __CYGWIN__
           if (user_handler != (sigsegv_handler_t) NULL
               && ExceptionInfo->ExceptionRecord->ExceptionCode == 
EXCEPTION_ACCESS_VIOLATION)
             {
@@ -192,6 +220,7 @@ main_exception_filter (EXCEPTION_POINTERS *ExceptionInfo)
               if ((*user_handler) (address, 1))
                 return EXCEPTION_CONTINUE_EXECUTION;
             }
+#endif /* __CYGWIN__ */
         }
     }
   return EXCEPTION_CONTINUE_SEARCH;
@@ -223,7 +252,7 @@ __asm__ (".equ __except_list,0");
 extern exception_list *_except_list __asm__ ("%fs:__except_list");

 /* For debugging.  _except_list is not otherwise accessible from gdb.  */
-static exception_list *
+static UNUSED exception_list *
 debug_get_except_list ()
 {
   return _except_list;
@@ -277,6 +306,7 @@ install_main_exception_filter ()
     }
 }

+#ifndef __CYGWIN__
 int
 sigsegv_install_handler (sigsegv_handler_t handler)
 {
@@ -298,6 +328,7 @@ sigsegv_leave_handler (void (*continuation) (void*, void*, 
void*),
   (*continuation) (cont_arg1, cont_arg2, cont_arg3);
   return 1;
 }
+#endif /* __CYGWIN__ */

 int
 stackoverflow_install_handler (stackoverflow_handler_t handler,
-- 
1.6.3.3.334.g916e1


>From 0f42bc874147fd2bcb494d4018936cd79bf6a255 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Wed, 22 Jul 2009 22:03:19 -0600
Subject: [PATCH 3/3] Fix interaction with cygwin 1.5.

* configure.ac (CFG_FAULT): Support older cygwin.
* src/fault-cygwin.h: New file.
* src/handler-win32.c (main_exception_filter): Snoop the fault
address into a static variable, since the unix implementation
cannot rely on si_addr.
(sigsegv_install_handler): Wrap the Unix implementation.
* NEWS: Document this.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog           |   11 +++++++++++
 NEWS                |    2 +-
 configure.ac        |    7 ++++++-
 src/fault-cygwin.h  |   31 +++++++++++++++++++++++++++++++
 src/handler-win32.c |   17 +++++++++++++++++
 5 files changed, 66 insertions(+), 2 deletions(-)
 create mode 100644 src/fault-cygwin.h

diff --git a/ChangeLog b/ChangeLog
index 27ff60a..bc6e461 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2009-07-23  Eric Blake  <address@hidden>
+
+       Fix interaction with cygwin 1.5.
+       * configure.ac (CFG_FAULT): Support older cygwin.
+       * src/fault-cygwin.h: New file.
+       * src/handler-win32.c (main_exception_filter): Snoop the fault
+       address into a static variable, since the unix implementation
+       cannot rely on si_addr.
+       (sigsegv_install_handler): Wrap the Unix implementation.
+       * NEWS: Document this.
+
 2009-07-22  Eric Blake  <address@hidden>

        Fix interaction with cygwin 1.7.
diff --git a/NEWS b/NEWS
index 6e6669b..fdccc34 100644
--- a/NEWS
+++ b/NEWS
@@ -3,7 +3,7 @@ New in 2.7:
 * Support for platforms that follow POSIX:2008, not POSIX:2001.
 * Support for MirBSD 10.
 * Support for IRIX 5.3. Contributed by Eric Blake.
-* Improved support for Cygwin 1.7. Contributed by Eric Blake.
+* Improved support for Cygwin 1.5 and 1.7. Contributed by Eric Blake.

 New in 2.6:

diff --git a/configure.ac b/configure.ac
index 1393642..3b6bcba 100644
--- a/configure.ac
+++ b/configure.ac
@@ -438,7 +438,12 @@ if test -z "$CFG_FAULT" && test 
"$sv_cv_fault_macosdarwin5_ppc" = yes; then
 fi
 if test -z "$CFG_FAULT"; then
   case "$host_os" in
-    mingw* | cygwin*)
+    cygwin*)
+      # Cygwin 1.7 uses fault-posix.h, but cygwin 1.5 needs help.
+      FAULT_CONTEXT='void'
+      CFG_FAULT=fault-cygwin.h
+      ;;
+    mingw*)
       FAULT_CONTEXT='CONTEXT'
       FAULT_CONTEXT_INCLUDE='#include <windows.h>'
       CFG_FAULT=fault-win32.h # nonexistent, just a dummy
diff --git a/src/fault-cygwin.h b/src/fault-cygwin.h
new file mode 100644
index 0000000..217cf69
--- /dev/null
+++ b/src/fault-cygwin.h
@@ -0,0 +1,31 @@
+/* Fault handler information.  Cygwin 1.5.x version.
+   Copyright (C) 2009  Eric Blake <address@hidden>
+
+   This program 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 2, or (at your option)
+   any later version.
+
+   This program 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, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* Cygwin cannot capture stack overflow without installing a W32 SEH
+   handler.  But not all SEH faults are SIGSEGV, since cygwin handles
+   some faults internally, such as EFAULT returns from syscalls.
+   Meanwhile, cygwin 1.5.x sets siginfo_t.si_addr to the instruction
+   the faulted, not the address that the instruction tried to access
+   (this was fixed in cygwin 1.7).  But since we already have to use
+   an SEH handler, we can use it to snoop the fault address before
+   passing on to cygwin to decide if it is a SIGSEGV.  */
+static void *sigsegv_fault_addr;
+
+#define SIGSEGV_FAULT_HANDLER_ARGLIST  int sig, siginfo_t *sip, void *context
+#define SIGSEGV_FAULT_ADDRESS  sigsegv_fault_addr
+#define SIGSEGV_FAULT_ADDRESS_FROM_SIGINFO
+#define SIGSEGV_FAULT_ADDRESS_FROM_SEH
diff --git a/src/handler-win32.c b/src/handler-win32.c
index a48ad8f..6d1c690 100644
--- a/src/handler-win32.c
+++ b/src/handler-win32.c
@@ -47,9 +47,11 @@
 # define HAVE_STACK_OVERFLOW_RECOVERY 0
 # define stackoverflow_install_handler stackoverflow_install_handler_dummy
 # define stackoverflow_deinstall_handler stackoverflow_deinstall_handler_dummy
+# define sigsegv_install_handler sigsegv_install_handler_real
 # include "handler-unix.c"
 # undef stackoverflow_install_handler
 # undef stackoverflow_deinstall_handler
+# undef sigsegv_install_handler

 #else
 /* User's SIGSEGV handler.  */
@@ -152,6 +154,8 @@ main_exception_filter (EXCEPTION_POINTERS *ExceptionInfo)
       ||
       (user_handler != (sigsegv_handler_t)NULL
        && ExceptionInfo->ExceptionRecord->ExceptionCode == 
EXCEPTION_ACCESS_VIOLATION)
+#elif defined SIGSEGV_FAULT_ADDRESS_FROM_SEH
+      || ExceptionInfo->ExceptionRecord->ExceptionCode == 
EXCEPTION_ACCESS_VIOLATION
 #endif
       )
     {
@@ -220,6 +224,8 @@ main_exception_filter (EXCEPTION_POINTERS *ExceptionInfo)
               if ((*user_handler) (address, 1))
                 return EXCEPTION_CONTINUE_EXECUTION;
             }
+#elif defined SIGSEGV_FAULT_ADDRESS_FROM_SEH
+         sigsegv_fault_addr = (void *) 
ExceptionInfo->ExceptionRecord->ExceptionInformation[1];
 #endif /* __CYGWIN__ */
         }
     }
@@ -328,6 +334,17 @@ sigsegv_leave_handler (void (*continuation) (void*, void*, 
void*),
   (*continuation) (cont_arg1, cont_arg2, cont_arg3);
   return 1;
 }
+
+#else /* __CYGWIN__ */
+int
+sigsegv_install_handler (sigsegv_handler_t handler)
+{
+#ifdef SIGSEGV_FAULT_ADDRESS_FROM_SEH
+  install_main_exception_filter ();
+#endif
+  return sigsegv_install_handler_real (handler);
+}
+
 #endif /* __CYGWIN__ */

 int
-- 
1.6.3.3.334.g916e1


reply via email to

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