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