From: Bruno Haible Date: Sun, 25 Sep 2011 19:05:20 +0000 (+0200) Subject: msvc-inval: Install handler globally. X-Git-Tag: v0.1~1742 X-Git-Url: http://erislabs.org.uk/gitweb/?a=commitdiff_plain;h=07edb02c97efe29a68bf5acd6cc3fcb0f7e79582;p=gnulib.git 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. --- diff --git a/ChangeLog b/ChangeLog index af8ce6038..73ad1b0e8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,21 @@ 2011-09-25 Bruno Haible + 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 + strerror_r-posix: Fix for MSVC 9. * lib/strerror_r.c (local_snprintf): New function. (snprintf): Define to local_snprintf, not to _snprintf. diff --git a/lib/msvc-inval.c b/lib/msvc-inval.c index 4e6fd3401..4618455fa 100644 --- a/lib/msvc-inval.c +++ b/lib/msvc-inval.c @@ -22,11 +22,11 @@ #if HAVE_MSVC_INVALID_PARAMETER_HANDLER -# ifdef STATUS_GNULIB_INVALID_PARAMETER - /* Get declarations of the Win32 API functions. */ -# define WIN32_LEAN_AND_MEAN -# include +# define WIN32_LEAN_AND_MEAN +# include + +# 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 diff --git a/lib/msvc-inval.h b/lib/msvc-inval.h index d76c56d7e..952e72ae9 100644 --- a/lib/msvc-inval.h +++ b/lib/msvc-inval.h @@ -47,14 +47,7 @@ /* Get _invalid_parameter_handler type and _set_invalid_parameter_handler declaration. */ # include - -# if defined _MSC_VER -/* A compiler that supports __try/__except, as described in the page - "try-except statement" on microsoft.com - . - With __try/__except, we can use the multithread-safe exception handling. */ - -# include +# include /* Gnulib can define its own status codes, as described in the page "Raising Software Exceptions" on microsoft.com @@ -64,7 +57,13 @@ - 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 + . + 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 @@ -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 \ } \ } \