1 /* Invalid parameter handler for MSVC runtime libraries.
2 Copyright (C) 2011 Free Software Foundation, Inc.
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 2, or (at your option)
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.
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
21 /* With MSVC runtime libraries with the "invalid parameter handler" concept,
22 functions like fprintf(), dup2(), or close() crash when the caller passes
23 an invalid argument. But POSIX wants error codes (such as EINVAL or EBADF)
25 This file defines macros that turn such an invalid parameter notification
26 into a non-local exit. An error code can then be produced at the target
27 of this exit. You can thus write code like
31 <Code that can trigger an invalid parameter notification
32 but does not do 'return', 'break', 'continue', nor 'goto'.>
36 <Code that handles an invalid parameter notification
37 but does not do 'return', 'break', 'continue', nor 'goto'.>
41 This entire block expands to a single statement.
44 #if HAVE_MSVC_INVALID_PARAMETER_HANDLER
45 /* A native Windows platform with the "invalid parameter handler" concept. */
47 /* Get _invalid_parameter_handler type and _set_invalid_parameter_handler
52 /* A compiler that supports __try/__except, as described in the page
53 "try-except statement" on microsoft.com
54 <http://msdn.microsoft.com/en-us/library/s58ftw19.aspx>.
55 With __try/__except, we can use the multithread-safe exception handling. */
57 /* Gnulib can define its own status codes, as described in the page
58 "Raising Software Exceptions" on microsoft.com
59 <http://msdn.microsoft.com/en-us/library/het71c37.aspx>.
60 Our status codes are composed of
61 - 0xE0000000, mandatory for all user-defined status codes,
62 - 0x474E550, a API identifier ("GNU"),
63 - 0, 1, 2, ..., used to distinguish different status codes from the
65 # define STATUS_GNULIB_INVALID_PARAMETER (0xE0000000 + 0x474E550 + 0)
71 /* Ensure that the invalid parameter handler in installed that raises a
72 software exception with code STATUS_GNULIB_INVALID_PARAMETER.
73 Because we assume no other part of the program installs a different
74 invalid parameter handler, this solution is multithread-safe. */
75 extern void gl_msvc_inval_ensure_handler (void);
81 # define TRY_MSVC_INVAL \
83 gl_msvc_inval_ensure_handler (); \
85 # define CATCH_MSVC_INVAL \
86 __except (GetExceptionCode () == STATUS_GNULIB_INVALID_PARAMETER \
87 ? EXCEPTION_EXECUTE_HANDLER \
88 : EXCEPTION_CONTINUE_SEARCH)
89 # define DONE_MSVC_INVAL \
94 We can only use setjmp/longjmp.
95 Unfortunately, this is *not* multithread-safe. */
103 /* The restart that will resume execution at the code between
104 CATCH_MSVC_INVAL and DONE_MSVC_INVAL. It is enabled only between
105 TRY_MSVC_INVAL and CATCH_MSVC_INVAL. */
106 extern jmp_buf gl_msvc_inval_restart;
108 /* The invalid parameter handler that unwinds the stack up to the
109 gl_msvc_inval_restart. It is enabled only between TRY_MSVC_INVAL
110 and CATCH_MSVC_INVAL. */
111 extern void cdecl gl_msvc_invalid_parameter_handler (const wchar_t *expression,
112 const wchar_t *function,
121 # define TRY_MSVC_INVAL \
123 _invalid_parameter_handler orig_handler; \
124 /* First, initialize gl_msvc_inval_restart. */ \
125 if (setjmp (gl_msvc_inval_restart) == 0) \
127 /* Then, enable gl_msvc_invalid_parameter_handler. */ \
129 _set_invalid_parameter_handler (gl_msvc_invalid_parameter_handler);
130 # define CATCH_MSVC_INVAL \
131 /* Execution completed. \
132 Disable gl_msvc_invalid_parameter_handler. */ \
133 _set_invalid_parameter_handler (orig_handler); \
137 /* Execution triggered an invalid parameter notification. \
138 Disable gl_msvc_invalid_parameter_handler. */ \
139 _set_invalid_parameter_handler (orig_handler);
140 # define DONE_MSVC_INVAL \
147 /* A platform that does not need to the invalid parameter handler. */
149 /* The braces here avoid GCC warnings like
150 "warning: suggest explicit braces to avoid ambiguous `else'". */
151 # define TRY_MSVC_INVAL { if (1)
152 # define CATCH_MSVC_INVAL else
153 # define DONE_MSVC_INVAL }
157 #endif /* _MSVC_INVAL_H */