105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Invalid parameter handler for MSVC runtime libraries.
205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Copyright (C) 2011-2012 Free Software Foundation, Inc.
305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
405436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is free software; you can redistribute it and/or modify
505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   it under the terms of the GNU General Public License as published by
605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   the Free Software Foundation; either version 3, or (at your option)
705436638acc7c010349a69c3395f1a57c642dc62Ying Wang   any later version.
805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
905436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is distributed in the hope that it will be useful,
1005436638acc7c010349a69c3395f1a57c642dc62Ying Wang   but WITHOUT ANY WARRANTY; without even the implied warranty of
1105436638acc7c010349a69c3395f1a57c642dc62Ying Wang   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   GNU General Public License for more details.
1305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1405436638acc7c010349a69c3395f1a57c642dc62Ying Wang   You should have received a copy of the GNU General Public License along
1505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   with this program; if not, see <http://www.gnu.org/licenses/>.  */
1605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#ifndef _MSVC_INVAL_H
1805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#define _MSVC_INVAL_H
1905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2005436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* With MSVC runtime libraries with the "invalid parameter handler" concept,
2105436638acc7c010349a69c3395f1a57c642dc62Ying Wang   functions like fprintf(), dup2(), or close() crash when the caller passes
2205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   an invalid argument.  But POSIX wants error codes (such as EINVAL or EBADF)
2305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   instead.
2405436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This file defines macros that turn such an invalid parameter notification
2505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   into a non-local exit.  An error code can then be produced at the target
2605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   of this exit.  You can thus write code like
2705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
2805436638acc7c010349a69c3395f1a57c642dc62Ying Wang     TRY_MSVC_INVAL
2905436638acc7c010349a69c3395f1a57c642dc62Ying Wang       {
3005436638acc7c010349a69c3395f1a57c642dc62Ying Wang         <Code that can trigger an invalid parameter notification
3105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          but does not do 'return', 'break', 'continue', nor 'goto'.>
3205436638acc7c010349a69c3395f1a57c642dc62Ying Wang       }
3305436638acc7c010349a69c3395f1a57c642dc62Ying Wang     CATCH_MSVC_INVAL
3405436638acc7c010349a69c3395f1a57c642dc62Ying Wang       {
3505436638acc7c010349a69c3395f1a57c642dc62Ying Wang         <Code that handles an invalid parameter notification
3605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          but does not do 'return', 'break', 'continue', nor 'goto'.>
3705436638acc7c010349a69c3395f1a57c642dc62Ying Wang       }
3805436638acc7c010349a69c3395f1a57c642dc62Ying Wang     DONE_MSVC_INVAL;
3905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
4005436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This entire block expands to a single statement.
4105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
4205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   The handling of invalid parameters can be done in three ways:
4305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
4405436638acc7c010349a69c3395f1a57c642dc62Ying Wang     * The default way, which is reasonable for programs (not libraries):
4505436638acc7c010349a69c3395f1a57c642dc62Ying Wang       AC_DEFINE([MSVC_INVALID_PARAMETER_HANDLING], [DEFAULT_HANDLING])
4605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
4705436638acc7c010349a69c3395f1a57c642dc62Ying Wang     * The way for libraries that make "hairy" calls (like close(-1), or
4805436638acc7c010349a69c3395f1a57c642dc62Ying Wang       fclose(fp) where fileno(fp) is closed, or simply getdtablesize()):
4905436638acc7c010349a69c3395f1a57c642dc62Ying Wang       AC_DEFINE([MSVC_INVALID_PARAMETER_HANDLING], [HAIRY_LIBRARY_HANDLING])
5005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
5105436638acc7c010349a69c3395f1a57c642dc62Ying Wang     * The way for libraries that make no "hairy" calls:
5205436638acc7c010349a69c3395f1a57c642dc62Ying Wang       AC_DEFINE([MSVC_INVALID_PARAMETER_HANDLING], [SANE_LIBRARY_HANDLING])
5305436638acc7c010349a69c3395f1a57c642dc62Ying Wang */
5405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
5505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#define DEFAULT_HANDLING       0
5605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#define HAIRY_LIBRARY_HANDLING 1
5705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#define SANE_LIBRARY_HANDLING  2
5805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
5905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if HAVE_MSVC_INVALID_PARAMETER_HANDLER \
6005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    && !(MSVC_INVALID_PARAMETER_HANDLING == SANE_LIBRARY_HANDLING)
6105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* A native Windows platform with the "invalid parameter handler" concept,
6205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   and either DEFAULT_HANDLING or HAIRY_LIBRARY_HANDLING.  */
6305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
6405436638acc7c010349a69c3395f1a57c642dc62Ying Wang# if MSVC_INVALID_PARAMETER_HANDLING == DEFAULT_HANDLING
6505436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Default handling.  */
6605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
6705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  ifdef __cplusplus
6805436638acc7c010349a69c3395f1a57c642dc62Ying Wangextern "C" {
6905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  endif
7005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
7105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Ensure that the invalid parameter handler in installed that just returns.
7205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Because we assume no other part of the program installs a different
7305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   invalid parameter handler, this solution is multithread-safe.  */
7405436638acc7c010349a69c3395f1a57c642dc62Ying Wangextern void gl_msvc_inval_ensure_handler (void);
7505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
7605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  ifdef __cplusplus
7705436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
7805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  endif
7905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
8005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  define TRY_MSVC_INVAL \
8105436638acc7c010349a69c3395f1a57c642dc62Ying Wang     do                                                                        \
8205436638acc7c010349a69c3395f1a57c642dc62Ying Wang       {                                                                       \
8305436638acc7c010349a69c3395f1a57c642dc62Ying Wang         gl_msvc_inval_ensure_handler ();                                      \
8405436638acc7c010349a69c3395f1a57c642dc62Ying Wang         if (1)
8505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  define CATCH_MSVC_INVAL \
8605436638acc7c010349a69c3395f1a57c642dc62Ying Wang         else
8705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  define DONE_MSVC_INVAL \
8805436638acc7c010349a69c3395f1a57c642dc62Ying Wang       }                                                                       \
8905436638acc7c010349a69c3395f1a57c642dc62Ying Wang     while (0)
9005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
9105436638acc7c010349a69c3395f1a57c642dc62Ying Wang# else
9205436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Handling for hairy libraries.  */
9305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
9405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  include <excpt.h>
9505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
9605436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Gnulib can define its own status codes, as described in the page
9705436638acc7c010349a69c3395f1a57c642dc62Ying Wang   "Raising Software Exceptions" on microsoft.com
9805436638acc7c010349a69c3395f1a57c642dc62Ying Wang   <http://msdn.microsoft.com/en-us/library/het71c37.aspx>.
9905436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Our status codes are composed of
10005436638acc7c010349a69c3395f1a57c642dc62Ying Wang     - 0xE0000000, mandatory for all user-defined status codes,
10105436638acc7c010349a69c3395f1a57c642dc62Ying Wang     - 0x474E550, a API identifier ("GNU"),
10205436638acc7c010349a69c3395f1a57c642dc62Ying Wang     - 0, 1, 2, ..., used to distinguish different status codes from the
10305436638acc7c010349a69c3395f1a57c642dc62Ying Wang       same API.  */
10405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  define STATUS_GNULIB_INVALID_PARAMETER (0xE0000000 + 0x474E550 + 0)
10505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
10605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  if defined _MSC_VER
10705436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* A compiler that supports __try/__except, as described in the page
10805436638acc7c010349a69c3395f1a57c642dc62Ying Wang   "try-except statement" on microsoft.com
10905436638acc7c010349a69c3395f1a57c642dc62Ying Wang   <http://msdn.microsoft.com/en-us/library/s58ftw19.aspx>.
11005436638acc7c010349a69c3395f1a57c642dc62Ying Wang   With __try/__except, we can use the multithread-safe exception handling.  */
11105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
11205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#   ifdef __cplusplus
11305436638acc7c010349a69c3395f1a57c642dc62Ying Wangextern "C" {
11405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#   endif
11505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
11605436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Ensure that the invalid parameter handler in installed that raises a
11705436638acc7c010349a69c3395f1a57c642dc62Ying Wang   software exception with code STATUS_GNULIB_INVALID_PARAMETER.
11805436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Because we assume no other part of the program installs a different
11905436638acc7c010349a69c3395f1a57c642dc62Ying Wang   invalid parameter handler, this solution is multithread-safe.  */
12005436638acc7c010349a69c3395f1a57c642dc62Ying Wangextern void gl_msvc_inval_ensure_handler (void);
12105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
12205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#   ifdef __cplusplus
12305436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
12405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#   endif
12505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
12605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#   define TRY_MSVC_INVAL \
12705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      do                                                                       \
12805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {                                                                      \
12905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          gl_msvc_inval_ensure_handler ();                                     \
13005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          __try
13105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#   define CATCH_MSVC_INVAL \
13205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          __except (GetExceptionCode () == STATUS_GNULIB_INVALID_PARAMETER     \
13305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    ? EXCEPTION_EXECUTE_HANDLER                                \
13405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    : EXCEPTION_CONTINUE_SEARCH)
13505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#   define DONE_MSVC_INVAL \
13605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }                                                                      \
13705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      while (0)
13805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
13905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  else
14005436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Any compiler.
14105436638acc7c010349a69c3395f1a57c642dc62Ying Wang   We can only use setjmp/longjmp.  */
14205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
14305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#   include <setjmp.h>
14405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
14505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#   ifdef __cplusplus
14605436638acc7c010349a69c3395f1a57c642dc62Ying Wangextern "C" {
14705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#   endif
14805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
14905436638acc7c010349a69c3395f1a57c642dc62Ying Wangstruct gl_msvc_inval_per_thread
15005436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
15105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* The restart that will resume execution at the code between
15205436638acc7c010349a69c3395f1a57c642dc62Ying Wang     CATCH_MSVC_INVAL and DONE_MSVC_INVAL.  It is enabled only between
15305436638acc7c010349a69c3395f1a57c642dc62Ying Wang     TRY_MSVC_INVAL and CATCH_MSVC_INVAL.  */
15405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  jmp_buf restart;
15505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
15605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  /* Tells whether the contents of restart is valid.  */
15705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  int restart_valid;
15805436638acc7c010349a69c3395f1a57c642dc62Ying Wang};
15905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
16005436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Ensure that the invalid parameter handler in installed that passes
16105436638acc7c010349a69c3395f1a57c642dc62Ying Wang   control to the gl_msvc_inval_restart if it is valid, or raises a
16205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   software exception with code STATUS_GNULIB_INVALID_PARAMETER otherwise.
16305436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Because we assume no other part of the program installs a different
16405436638acc7c010349a69c3395f1a57c642dc62Ying Wang   invalid parameter handler, this solution is multithread-safe.  */
16505436638acc7c010349a69c3395f1a57c642dc62Ying Wangextern void gl_msvc_inval_ensure_handler (void);
16605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
16705436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Return a pointer to the per-thread data for the current thread.  */
16805436638acc7c010349a69c3395f1a57c642dc62Ying Wangextern struct gl_msvc_inval_per_thread *gl_msvc_inval_current (void);
16905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
17005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#   ifdef __cplusplus
17105436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
17205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#   endif
17305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
17405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#   define TRY_MSVC_INVAL \
17505436638acc7c010349a69c3395f1a57c642dc62Ying Wang      do                                                                       \
17605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {                                                                      \
17705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          struct gl_msvc_inval_per_thread *msvc_inval_current;                 \
17805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          gl_msvc_inval_ensure_handler ();                                     \
17905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          msvc_inval_current = gl_msvc_inval_current ();                       \
18005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* First, initialize gl_msvc_inval_restart.  */                      \
18105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (setjmp (msvc_inval_current->restart) == 0)                       \
18205436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {                                                                  \
18305436638acc7c010349a69c3395f1a57c642dc62Ying Wang              /* Then, mark it as valid.  */                                   \
18405436638acc7c010349a69c3395f1a57c642dc62Ying Wang              msvc_inval_current->restart_valid = 1;
18505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#   define CATCH_MSVC_INVAL \
18605436638acc7c010349a69c3395f1a57c642dc62Ying Wang              /* Execution completed.                                          \
18705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                 Mark gl_msvc_inval_restart as invalid.  */                    \
18805436638acc7c010349a69c3395f1a57c642dc62Ying Wang              msvc_inval_current->restart_valid = 0;                           \
18905436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }                                                                  \
19005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          else                                                                 \
19105436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {                                                                  \
19205436638acc7c010349a69c3395f1a57c642dc62Ying Wang              /* Execution triggered an invalid parameter notification.        \
19305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                 Mark gl_msvc_inval_restart as invalid.  */                    \
19405436638acc7c010349a69c3395f1a57c642dc62Ying Wang              msvc_inval_current->restart_valid = 0;
19505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#   define DONE_MSVC_INVAL \
19605436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }                                                                  \
19705436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }                                                                      \
19805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      while (0)
19905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
20005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  endif
20105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
20205436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif
20305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
20405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#else
20505436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* A platform that does not need to the invalid parameter handler,
20605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   or when SANE_LIBRARY_HANDLING is desired.  */
20705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
20805436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* The braces here avoid GCC warnings like
20905436638acc7c010349a69c3395f1a57c642dc62Ying Wang   "warning: suggest explicit braces to avoid ambiguous 'else'".  */
21005436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define TRY_MSVC_INVAL \
21105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    do                                                                         \
21205436638acc7c010349a69c3395f1a57c642dc62Ying Wang      {                                                                        \
21305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        if (1)
21405436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define CATCH_MSVC_INVAL \
21505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        else
21605436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define DONE_MSVC_INVAL \
21705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      }                                                                        \
21805436638acc7c010349a69c3395f1a57c642dc62Ying Wang    while (0)
21905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
22005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
22105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
22205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif /* _MSVC_INVAL_H */
223