msvc-inval: Install handler globally.
authorBruno Haible <bruno@clisp.org>
Sun, 25 Sep 2011 19:05:20 +0000 (21:05 +0200)
committerBruno Haible <bruno@clisp.org>
Sun, 25 Sep 2011 19:05:20 +0000 (21:05 +0200)
* lib/msvc-inval.h (STATUS_GNULIB_INVALID_PARAMETER): Define also for
!_MSC_VER.
(gl_msvc_invalid_parameter_handler): Remove declaration.
(gl_msvc_inval_restart_valid, gl_msvc_inval_ensure_handler): New
declarations.
(TRY_MSVC_INVAL, CATCH_MSVC_INVAL, DONE_MSVC_INVAL) [!_MSC_VER]:
Install the handler globally, don't uninstall it.
* lib/msvc-inval.c (gl_msvc_inval_restart_valid): New variable.
(gl_msvc_invalid_parameter_handler): Make static. If the restart is not
currently valid, call RaiseException instead.
(gl_msvc_inval_initialized, gl_msvc_inval_ensure_handler): Define also
for !_MSC_VER.

ChangeLog
lib/msvc-inval.c
lib/msvc-inval.h

index af8ce60..73ad1b0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,21 @@
 2011-09-25  Bruno Haible  <bruno@clisp.org>
 
+       msvc-inval: Install handler globally.
+       * lib/msvc-inval.h (STATUS_GNULIB_INVALID_PARAMETER): Define also for
+       !_MSC_VER.
+       (gl_msvc_invalid_parameter_handler): Remove declaration.
+       (gl_msvc_inval_restart_valid, gl_msvc_inval_ensure_handler): New
+       declarations.
+       (TRY_MSVC_INVAL, CATCH_MSVC_INVAL, DONE_MSVC_INVAL) [!_MSC_VER]:
+       Install the handler globally, don't uninstall it.
+       * lib/msvc-inval.c (gl_msvc_inval_restart_valid): New variable.
+       (gl_msvc_invalid_parameter_handler): Make static. If the restart is not
+       currently valid, call RaiseException instead.
+       (gl_msvc_inval_initialized, gl_msvc_inval_ensure_handler): Define also
+       for !_MSC_VER.
+
+2011-09-25  Bruno Haible  <bruno@clisp.org>
+
        strerror_r-posix: Fix for MSVC 9.
        * lib/strerror_r.c (local_snprintf): New function.
        (snprintf): Define to local_snprintf, not to _snprintf.
index 4e6fd34..4618455 100644 (file)
 
 #if HAVE_MSVC_INVALID_PARAMETER_HANDLER
 
-# ifdef STATUS_GNULIB_INVALID_PARAMETER
-
 /* Get declarations of the Win32 API functions.  */
-#  define WIN32_LEAN_AND_MEAN
-#  include <windows.h>
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+
+# if defined _MSC_VER
 
 static void cdecl
 gl_msvc_invalid_parameter_handler (const wchar_t *expression,
@@ -38,32 +38,38 @@ gl_msvc_invalid_parameter_handler (const wchar_t *expression,
   RaiseException (STATUS_GNULIB_INVALID_PARAMETER, 0, 0, NULL);
 }
 
-static int gl_msvc_inval_initialized /* = 0 */;
-
-void
-gl_msvc_inval_ensure_handler (void)
-{
-  if (gl_msvc_inval_initialized == 0)
-    {
-      _set_invalid_parameter_handler (gl_msvc_invalid_parameter_handler);
-      gl_msvc_inval_initialized = 1;
-    }
-}
-
 # else
 
 jmp_buf gl_msvc_inval_restart;
+int gl_msvc_inval_restart_valid;
 
-void cdecl
+static void cdecl
 gl_msvc_invalid_parameter_handler (const wchar_t *expression,
                                    const wchar_t *function,
                                    const wchar_t *file,
                                    unsigned int line,
                                    uintptr_t dummy)
 {
-  longjmp (gl_msvc_inval_restart, 1);
+  if (gl_msvc_inval_restart_valid)
+    longjmp (gl_msvc_inval_restart, 1);
+  else
+    /* An invalid parameter notification from outside the gnulib code.
+       Give the caller a chance to intervene.  */
+    RaiseException (STATUS_GNULIB_INVALID_PARAMETER, 0, 0, NULL);
 }
 
 # endif
 
+static int gl_msvc_inval_initialized /* = 0 */;
+
+void
+gl_msvc_inval_ensure_handler (void)
+{
+  if (gl_msvc_inval_initialized == 0)
+    {
+      _set_invalid_parameter_handler (gl_msvc_invalid_parameter_handler);
+      gl_msvc_inval_initialized = 1;
+    }
+}
+
 #endif
index d76c56d..952e72a 100644 (file)
 /* Get _invalid_parameter_handler type and _set_invalid_parameter_handler
    declaration.  */
 # include <stdlib.h>
-
-# if defined _MSC_VER
-/* A compiler that supports __try/__except, as described in the page
-   "try-except statement" on microsoft.com
-   <http://msdn.microsoft.com/en-us/library/s58ftw19.aspx>.
-   With __try/__except, we can use the multithread-safe exception handling.  */
-
-#  include <excpt.h>
+# include <excpt.h>
 
 /* Gnulib can define its own status codes, as described in the page
    "Raising Software Exceptions" on microsoft.com
      - 0x474E550, a API identifier ("GNU"),
      - 0, 1, 2, ..., used to distinguish different status codes from the
        same API.  */
-#  define STATUS_GNULIB_INVALID_PARAMETER (0xE0000000 + 0x474E550 + 0)
+# define STATUS_GNULIB_INVALID_PARAMETER (0xE0000000 + 0x474E550 + 0)
+
+# if defined _MSC_VER
+/* A compiler that supports __try/__except, as described in the page
+   "try-except statement" on microsoft.com
+   <http://msdn.microsoft.com/en-us/library/s58ftw19.aspx>.
+   With __try/__except, we can use the multithread-safe exception handling.  */
 
 #  ifdef __cplusplus
 extern "C" {
@@ -95,8 +94,7 @@ extern void gl_msvc_inval_ensure_handler (void);
 
 # else
 /* Any compiler.
-   We can only use setjmp/longjmp.
-   Unfortunately, this is *not* multithread-safe.  */
+   We can only use setjmp/longjmp.  */
 
 #  include <setjmp.h>
 
@@ -109,14 +107,15 @@ extern "C" {
    TRY_MSVC_INVAL and CATCH_MSVC_INVAL.  */
 extern jmp_buf gl_msvc_inval_restart;
 
-/* The invalid parameter handler that unwinds the stack up to the
-   gl_msvc_inval_restart.  It is enabled only between TRY_MSVC_INVAL
-   and CATCH_MSVC_INVAL.  */
-extern void cdecl gl_msvc_invalid_parameter_handler (const wchar_t *expression,
-                                                     const wchar_t *function,
-                                                     const wchar_t *file,
-                                                     unsigned int line,
-                                                     uintptr_t dummy);
+/* Tells whether the contents of gl_msvc_inval_restart is valid.  */
+extern int gl_msvc_inval_restart_valid;
+
+/* Ensure that the invalid parameter handler in installed that passes
+   control to the gl_msvc_inval_restart if it is valid, or raises a
+   software exception with code STATUS_GNULIB_INVALID_PARAMETER otherwise.
+   Because we assume no other part of the program installs a different
+   invalid parameter handler, this solution is multithread-safe.  */
+extern void gl_msvc_inval_ensure_handler (void);
 
 #  ifdef __cplusplus
 }
@@ -125,23 +124,22 @@ extern void cdecl gl_msvc_invalid_parameter_handler (const wchar_t *expression,
 #  define TRY_MSVC_INVAL \
      do                                                                        \
        {                                                                       \
-         _invalid_parameter_handler orig_handler;                              \
+         gl_msvc_inval_ensure_handler ();                                      \
          /* First, initialize gl_msvc_inval_restart.  */                       \
          if (setjmp (gl_msvc_inval_restart) == 0)                              \
            {                                                                   \
-             /* Then, enable gl_msvc_invalid_parameter_handler.  */            \
-             orig_handler =                                                    \
-               _set_invalid_parameter_handler (gl_msvc_invalid_parameter_handler);
+             /* Then, mark it as valid.  */                                    \
+             gl_msvc_inval_restart_valid = 1;
 #  define CATCH_MSVC_INVAL \
              /* Execution completed.                                           \
-                Disable gl_msvc_invalid_parameter_handler.  */                 \
-             _set_invalid_parameter_handler (orig_handler);                    \
+                Mark gl_msvc_inval_restart as invalid.  */                     \
+             gl_msvc_inval_restart_valid = 0;                                  \
            }                                                                   \
          else                                                                  \
            {                                                                   \
              /* Execution triggered an invalid parameter notification.         \
-                Disable gl_msvc_invalid_parameter_handler.  */                 \
-             _set_invalid_parameter_handler (orig_handler);
+                Mark gl_msvc_inval_restart as invalid.  */                     \
+             gl_msvc_inval_restart_valid = 0;
 #  define DONE_MSVC_INVAL \
            }                                                                   \
        }                                                                       \