Home | History | Annotate | Download | only in lib
      1 /* Invalid parameter handler for MSVC runtime libraries.
      2    Copyright (C) 2011-2012 Free Software Foundation, Inc.
      3 
      4    This program is free software; you can redistribute it and/or modify
      5    it under the terms of the GNU General Public License as published by
      6    the Free Software Foundation; either version 3, or (at your option)
      7    any later version.
      8 
      9    This program is distributed in the hope that it will be useful,
     10    but WITHOUT ANY WARRANTY; without even the implied warranty of
     11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12    GNU General Public License for more details.
     13 
     14    You should have received a copy of the GNU General Public License along
     15    with this program; if not, see <http://www.gnu.org/licenses/>.  */
     16 
     17 #include <config.h>
     18 
     19 /* Specification.  */
     20 #include "msvc-inval.h"
     21 
     22 #if HAVE_MSVC_INVALID_PARAMETER_HANDLER \
     23     && !(MSVC_INVALID_PARAMETER_HANDLING == SANE_LIBRARY_HANDLING)
     24 
     25 /* Get _invalid_parameter_handler type and _set_invalid_parameter_handler
     26    declaration.  */
     27 # include <stdlib.h>
     28 
     29 # if MSVC_INVALID_PARAMETER_HANDLING == DEFAULT_HANDLING
     30 
     31 static void cdecl
     32 gl_msvc_invalid_parameter_handler (const wchar_t *expression,
     33                                    const wchar_t *function,
     34                                    const wchar_t *file,
     35                                    unsigned int line,
     36                                    uintptr_t dummy)
     37 {
     38 }
     39 
     40 # else
     41 
     42 /* Get declarations of the native Windows API functions.  */
     43 #  define WIN32_LEAN_AND_MEAN
     44 #  include <windows.h>
     45 
     46 #  if defined _MSC_VER
     47 
     48 static void cdecl
     49 gl_msvc_invalid_parameter_handler (const wchar_t *expression,
     50                                    const wchar_t *function,
     51                                    const wchar_t *file,
     52                                    unsigned int line,
     53                                    uintptr_t dummy)
     54 {
     55   RaiseException (STATUS_GNULIB_INVALID_PARAMETER, 0, 0, NULL);
     56 }
     57 
     58 #  else
     59 
     60 /* An index to thread-local storage.  */
     61 static DWORD tls_index;
     62 static int tls_initialized /* = 0 */;
     63 
     64 /* Used as a fallback only.  */
     65 static struct gl_msvc_inval_per_thread not_per_thread;
     66 
     67 struct gl_msvc_inval_per_thread *
     68 gl_msvc_inval_current (void)
     69 {
     70   if (!tls_initialized)
     71     {
     72       tls_index = TlsAlloc ();
     73       tls_initialized = 1;
     74     }
     75   if (tls_index == TLS_OUT_OF_INDEXES)
     76     /* TlsAlloc had failed.  */
     77     return &not_per_thread;
     78   else
     79     {
     80       struct gl_msvc_inval_per_thread *pointer =
     81         (struct gl_msvc_inval_per_thread *) TlsGetValue (tls_index);
     82       if (pointer == NULL)
     83         {
     84           /* First call.  Allocate a new 'struct gl_msvc_inval_per_thread'.  */
     85           pointer =
     86             (struct gl_msvc_inval_per_thread *)
     87             malloc (sizeof (struct gl_msvc_inval_per_thread));
     88           if (pointer == NULL)
     89             /* Could not allocate memory.  Use the global storage.  */
     90             pointer = &not_per_thread;
     91           TlsSetValue (tls_index, pointer);
     92         }
     93       return pointer;
     94     }
     95 }
     96 
     97 static void cdecl
     98 gl_msvc_invalid_parameter_handler (const wchar_t *expression,
     99                                    const wchar_t *function,
    100                                    const wchar_t *file,
    101                                    unsigned int line,
    102                                    uintptr_t dummy)
    103 {
    104   struct gl_msvc_inval_per_thread *current = gl_msvc_inval_current ();
    105   if (current->restart_valid)
    106     longjmp (current->restart, 1);
    107   else
    108     /* An invalid parameter notification from outside the gnulib code.
    109        Give the caller a chance to intervene.  */
    110     RaiseException (STATUS_GNULIB_INVALID_PARAMETER, 0, 0, NULL);
    111 }
    112 
    113 #  endif
    114 
    115 # endif
    116 
    117 static int gl_msvc_inval_initialized /* = 0 */;
    118 
    119 void
    120 gl_msvc_inval_ensure_handler (void)
    121 {
    122   if (gl_msvc_inval_initialized == 0)
    123     {
    124       _set_invalid_parameter_handler (gl_msvc_invalid_parameter_handler);
    125       gl_msvc_inval_initialized = 1;
    126     }
    127 }
    128 
    129 #endif
    130