msvc-inval.h 8.7 KB

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