18dffb485Schristos /* Invalid parameter handler for MSVC runtime libraries.
2*4b169a6bSchristos Copyright (C) 2011-2022 Free Software Foundation, Inc.
38dffb485Schristos
4*4b169a6bSchristos This file is free software: you can redistribute it and/or modify
5*4b169a6bSchristos it under the terms of the GNU Lesser General Public License as
6*4b169a6bSchristos published by the Free Software Foundation; either version 2.1 of the
7*4b169a6bSchristos License, or (at your option) any later version.
88dffb485Schristos
9*4b169a6bSchristos This file is distributed in the hope that it will be useful,
108dffb485Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
118dffb485Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12*4b169a6bSchristos GNU Lesser General Public License for more details.
138dffb485Schristos
14*4b169a6bSchristos You should have received a copy of the GNU Lesser General Public License
15*4b169a6bSchristos along with this program. If not, see <https://www.gnu.org/licenses/>. */
168dffb485Schristos
178dffb485Schristos #include <config.h>
188dffb485Schristos
198dffb485Schristos /* Specification. */
208dffb485Schristos #include "msvc-inval.h"
218dffb485Schristos
228dffb485Schristos #if HAVE_MSVC_INVALID_PARAMETER_HANDLER \
238dffb485Schristos && !(MSVC_INVALID_PARAMETER_HANDLING == SANE_LIBRARY_HANDLING)
248dffb485Schristos
258dffb485Schristos /* Get _invalid_parameter_handler type and _set_invalid_parameter_handler
268dffb485Schristos declaration. */
278dffb485Schristos # include <stdlib.h>
288dffb485Schristos
298dffb485Schristos # if MSVC_INVALID_PARAMETER_HANDLING == DEFAULT_HANDLING
308dffb485Schristos
318dffb485Schristos static void __cdecl
gl_msvc_invalid_parameter_handler(const wchar_t * expression,const wchar_t * function,const wchar_t * file,unsigned int line,uintptr_t dummy)328dffb485Schristos gl_msvc_invalid_parameter_handler (const wchar_t *expression,
338dffb485Schristos const wchar_t *function,
348dffb485Schristos const wchar_t *file,
358dffb485Schristos unsigned int line,
368dffb485Schristos uintptr_t dummy)
378dffb485Schristos {
388dffb485Schristos }
398dffb485Schristos
408dffb485Schristos # else
418dffb485Schristos
428dffb485Schristos /* Get declarations of the native Windows API functions. */
438dffb485Schristos # define WIN32_LEAN_AND_MEAN
448dffb485Schristos # include <windows.h>
458dffb485Schristos
468dffb485Schristos # if defined _MSC_VER
478dffb485Schristos
488dffb485Schristos static void __cdecl
gl_msvc_invalid_parameter_handler(const wchar_t * expression,const wchar_t * function,const wchar_t * file,unsigned int line,uintptr_t dummy)498dffb485Schristos gl_msvc_invalid_parameter_handler (const wchar_t *expression,
508dffb485Schristos const wchar_t *function,
518dffb485Schristos const wchar_t *file,
528dffb485Schristos unsigned int line,
538dffb485Schristos uintptr_t dummy)
548dffb485Schristos {
558dffb485Schristos RaiseException (STATUS_GNULIB_INVALID_PARAMETER, 0, 0, NULL);
568dffb485Schristos }
578dffb485Schristos
588dffb485Schristos # else
598dffb485Schristos
608dffb485Schristos /* An index to thread-local storage. */
618dffb485Schristos static DWORD tls_index;
628dffb485Schristos static int tls_initialized /* = 0 */;
638dffb485Schristos
648dffb485Schristos /* Used as a fallback only. */
658dffb485Schristos static struct gl_msvc_inval_per_thread not_per_thread;
668dffb485Schristos
678dffb485Schristos struct gl_msvc_inval_per_thread *
gl_msvc_inval_current(void)688dffb485Schristos gl_msvc_inval_current (void)
698dffb485Schristos {
708dffb485Schristos if (!tls_initialized)
718dffb485Schristos {
728dffb485Schristos tls_index = TlsAlloc ();
738dffb485Schristos tls_initialized = 1;
748dffb485Schristos }
758dffb485Schristos if (tls_index == TLS_OUT_OF_INDEXES)
768dffb485Schristos /* TlsAlloc had failed. */
778dffb485Schristos return ¬_per_thread;
788dffb485Schristos else
798dffb485Schristos {
808dffb485Schristos struct gl_msvc_inval_per_thread *pointer =
818dffb485Schristos (struct gl_msvc_inval_per_thread *) TlsGetValue (tls_index);
828dffb485Schristos if (pointer == NULL)
838dffb485Schristos {
848dffb485Schristos /* First call. Allocate a new 'struct gl_msvc_inval_per_thread'. */
858dffb485Schristos pointer =
868dffb485Schristos (struct gl_msvc_inval_per_thread *)
878dffb485Schristos malloc (sizeof (struct gl_msvc_inval_per_thread));
888dffb485Schristos if (pointer == NULL)
898dffb485Schristos /* Could not allocate memory. Use the global storage. */
908dffb485Schristos pointer = ¬_per_thread;
918dffb485Schristos TlsSetValue (tls_index, pointer);
928dffb485Schristos }
938dffb485Schristos return pointer;
948dffb485Schristos }
958dffb485Schristos }
968dffb485Schristos
978dffb485Schristos static void __cdecl
gl_msvc_invalid_parameter_handler(const wchar_t * expression,const wchar_t * function,const wchar_t * file,unsigned int line,uintptr_t dummy)988dffb485Schristos gl_msvc_invalid_parameter_handler (const wchar_t *expression,
998dffb485Schristos const wchar_t *function,
1008dffb485Schristos const wchar_t *file,
1018dffb485Schristos unsigned int line,
1028dffb485Schristos uintptr_t dummy)
1038dffb485Schristos {
1048dffb485Schristos struct gl_msvc_inval_per_thread *current = gl_msvc_inval_current ();
1058dffb485Schristos if (current->restart_valid)
1068dffb485Schristos longjmp (current->restart, 1);
1078dffb485Schristos else
1088dffb485Schristos /* An invalid parameter notification from outside the gnulib code.
1098dffb485Schristos Give the caller a chance to intervene. */
1108dffb485Schristos RaiseException (STATUS_GNULIB_INVALID_PARAMETER, 0, 0, NULL);
1118dffb485Schristos }
1128dffb485Schristos
1138dffb485Schristos # endif
1148dffb485Schristos
1158dffb485Schristos # endif
1168dffb485Schristos
1178dffb485Schristos static int gl_msvc_inval_initialized /* = 0 */;
1188dffb485Schristos
1198dffb485Schristos void
gl_msvc_inval_ensure_handler(void)1208dffb485Schristos gl_msvc_inval_ensure_handler (void)
1218dffb485Schristos {
1228dffb485Schristos if (gl_msvc_inval_initialized == 0)
1238dffb485Schristos {
1248dffb485Schristos _set_invalid_parameter_handler (gl_msvc_invalid_parameter_handler);
1258dffb485Schristos gl_msvc_inval_initialized = 1;
1268dffb485Schristos }
1278dffb485Schristos }
1288dffb485Schristos
1298dffb485Schristos #endif
130