root/maint/gnulib/lib/msvc-inval.h

/* [previous][next][first][last][top][bottom][index][help] */

INCLUDED FROM


   1 /* Invalid parameter handler for MSVC runtime libraries.
   2    Copyright (C) 2011-2021 Free Software Foundation, Inc.
   3 
   4    This file is free software: you can redistribute it and/or modify
   5    it under the terms of the GNU Lesser General Public License as
   6    published by the Free Software Foundation; either version 2.1 of the
   7    License, or (at your option) any later version.
   8 
   9    This file 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 Lesser General Public License for more details.
  13 
  14    You should have received a copy of the GNU Lesser General Public License
  15    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  16 
  17 #ifndef _MSVC_INVAL_H
  18 #define _MSVC_INVAL_H
  19 
  20 /* With MSVC runtime libraries with the "invalid parameter handler" concept,
  21    functions like fprintf(), dup2(), or close() crash when the caller passes
  22    an invalid argument.  But POSIX wants error codes (such as EINVAL or EBADF)
  23    instead.
  24    This file defines macros that turn such an invalid parameter notification
  25    into a non-local exit.  An error code can then be produced at the target
  26    of this exit.  You can thus write code like
  27 
  28      TRY_MSVC_INVAL
  29        {
  30          <Code that can trigger an invalid parameter notification
  31           but does not do 'return', 'break', 'continue', nor 'goto'.>
  32        }
  33      CATCH_MSVC_INVAL
  34        {
  35          <Code that handles an invalid parameter notification
  36           but does not do 'return', 'break', 'continue', nor 'goto'.>
  37        }
  38      DONE_MSVC_INVAL;
  39 
  40    This entire block expands to a single statement.
  41 
  42    The handling of invalid parameters can be done in three ways:
  43 
  44      * The default way, which is reasonable for programs (not libraries):
  45        AC_DEFINE([MSVC_INVALID_PARAMETER_HANDLING], [DEFAULT_HANDLING])
  46 
  47      * The way for libraries that make "hairy" calls (like close(-1), or
  48        fclose(fp) where fileno(fp) is closed, or simply getdtablesize()):
  49        AC_DEFINE([MSVC_INVALID_PARAMETER_HANDLING], [HAIRY_LIBRARY_HANDLING])
  50 
  51      * The way for libraries that make no "hairy" calls:
  52        AC_DEFINE([MSVC_INVALID_PARAMETER_HANDLING], [SANE_LIBRARY_HANDLING])
  53  */
  54 
  55 #define DEFAULT_HANDLING       0
  56 #define HAIRY_LIBRARY_HANDLING 1
  57 #define SANE_LIBRARY_HANDLING  2
  58 
  59 #if HAVE_MSVC_INVALID_PARAMETER_HANDLER \
  60     && !(MSVC_INVALID_PARAMETER_HANDLING == SANE_LIBRARY_HANDLING)
  61 /* A native Windows platform with the "invalid parameter handler" concept,
  62    and either DEFAULT_HANDLING or HAIRY_LIBRARY_HANDLING.  */
  63 
  64 # if MSVC_INVALID_PARAMETER_HANDLING == DEFAULT_HANDLING
  65 /* Default handling.  */
  66 
  67 #  ifdef __cplusplus
  68 extern "C" {
  69 #  endif
  70 
  71 /* Ensure that the invalid parameter handler in installed that just returns.
  72    Because we assume no other part of the program installs a different
  73    invalid parameter handler, this solution is multithread-safe.  */
  74 extern void gl_msvc_inval_ensure_handler (void);
  75 
  76 #  ifdef __cplusplus
  77 }
  78 #  endif
  79 
  80 #  define TRY_MSVC_INVAL \
  81      do                                                                        \
  82        {                                                                       \
  83          gl_msvc_inval_ensure_handler ();                                      \
  84          if (1)
  85 #  define CATCH_MSVC_INVAL \
  86          else
  87 #  define DONE_MSVC_INVAL \
  88        }                                                                       \
  89      while (0)
  90 
  91 # else
  92 /* Handling for hairy libraries.  */
  93 
  94 #  include <excpt.h>
  95 
  96 /* Gnulib can define its own status codes, as described in the page
  97    "Raising Software Exceptions" on microsoft.com
  98    <https://docs.microsoft.com/en-us/cpp/cpp/raising-software-exceptions>.
  99    Our status codes are composed of
 100      - 0xE0000000, mandatory for all user-defined status codes,
 101      - 0x474E550, a API identifier ("GNU"),
 102      - 0, 1, 2, ..., used to distinguish different status codes from the
 103        same API.  */
 104 #  define STATUS_GNULIB_INVALID_PARAMETER (0xE0000000 + 0x474E550 + 0)
 105 
 106 #  if defined _MSC_VER
 107 /* A compiler that supports __try/__except, as described in the page
 108    "try-except statement" on microsoft.com
 109    <https://docs.microsoft.com/en-us/cpp/cpp/try-except-statement>.
 110    With __try/__except, we can use the multithread-safe exception handling.  */
 111 
 112 #   ifdef __cplusplus
 113 extern "C" {
 114 #   endif
 115 
 116 /* Ensure that the invalid parameter handler in installed that raises a
 117    software exception with code STATUS_GNULIB_INVALID_PARAMETER.
 118    Because we assume no other part of the program installs a different
 119    invalid parameter handler, this solution is multithread-safe.  */
 120 extern void gl_msvc_inval_ensure_handler (void);
 121 
 122 #   ifdef __cplusplus
 123 }
 124 #   endif
 125 
 126 #   define TRY_MSVC_INVAL \
 127       do                                                                       \
 128         {                                                                      \
 129           gl_msvc_inval_ensure_handler ();                                     \
 130           __try
 131 #   define CATCH_MSVC_INVAL \
 132           __except (GetExceptionCode () == STATUS_GNULIB_INVALID_PARAMETER     \
 133                     ? EXCEPTION_EXECUTE_HANDLER                                \
 134                     : EXCEPTION_CONTINUE_SEARCH)
 135 #   define DONE_MSVC_INVAL \
 136         }                                                                      \
 137       while (0)
 138 
 139 #  else
 140 /* Any compiler.
 141    We can only use setjmp/longjmp.  */
 142 
 143 #   include <setjmp.h>
 144 
 145 #   ifdef __cplusplus
 146 extern "C" {
 147 #   endif
 148 
 149 struct gl_msvc_inval_per_thread
 150 {
 151   /* The restart that will resume execution at the code between
 152      CATCH_MSVC_INVAL and DONE_MSVC_INVAL.  It is enabled only between
 153      TRY_MSVC_INVAL and CATCH_MSVC_INVAL.  */
 154   jmp_buf restart;
 155 
 156   /* Tells whether the contents of restart is valid.  */
 157   int restart_valid;
 158 };
 159 
 160 /* Ensure that the invalid parameter handler in installed that passes
 161    control to the gl_msvc_inval_restart if it is valid, or raises a
 162    software exception with code STATUS_GNULIB_INVALID_PARAMETER otherwise.
 163    Because we assume no other part of the program installs a different
 164    invalid parameter handler, this solution is multithread-safe.  */
 165 extern void gl_msvc_inval_ensure_handler (void);
 166 
 167 /* Return a pointer to the per-thread data for the current thread.  */
 168 extern struct gl_msvc_inval_per_thread *gl_msvc_inval_current (void);
 169 
 170 #   ifdef __cplusplus
 171 }
 172 #   endif
 173 
 174 #   define TRY_MSVC_INVAL \
 175       do                                                                       \
 176         {                                                                      \
 177           struct gl_msvc_inval_per_thread *msvc_inval_current;                 \
 178           gl_msvc_inval_ensure_handler ();                                     \
 179           msvc_inval_current = gl_msvc_inval_current ();                       \
 180           /* First, initialize gl_msvc_inval_restart.  */                      \
 181           if (setjmp (msvc_inval_current->restart) == 0)                       \
 182             {                                                                  \
 183               /* Then, mark it as valid.  */                                   \
 184               msvc_inval_current->restart_valid = 1;
 185 #   define CATCH_MSVC_INVAL \
 186               /* Execution completed.                                          \
 187                  Mark gl_msvc_inval_restart as invalid.  */                    \
 188               msvc_inval_current->restart_valid = 0;                           \
 189             }                                                                  \
 190           else                                                                 \
 191             {                                                                  \
 192               /* Execution triggered an invalid parameter notification.        \
 193                  Mark gl_msvc_inval_restart as invalid.  */                    \
 194               msvc_inval_current->restart_valid = 0;
 195 #   define DONE_MSVC_INVAL \
 196             }                                                                  \
 197         }                                                                      \
 198       while (0)
 199 
 200 #  endif
 201 
 202 # endif
 203 
 204 #else
 205 /* A platform that does not need to the invalid parameter handler,
 206    or when SANE_LIBRARY_HANDLING is desired.  */
 207 
 208 /* The braces here avoid GCC warnings like
 209    "warning: suggest explicit braces to avoid ambiguous 'else'".  */
 210 # define TRY_MSVC_INVAL \
 211     do                                                                         \
 212       {                                                                        \
 213         if (1)
 214 # define CATCH_MSVC_INVAL \
 215         else
 216 # define DONE_MSVC_INVAL \
 217       }                                                                        \
 218     while (0)
 219 
 220 #endif
 221 
 222 #endif /* _MSVC_INVAL_H */

/* [previous][next][first][last][top][bottom][index][help] */