1 //
2 // invalid_parameter.cpp
3 //
4 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //
6 // The invalid parameter handlers and related functionality
7 //
8 #include <corecrt_internal.h>
9 #include <corecrt_internal_ptd_propagation.h>
10
11
12 static __crt_state_management::dual_state_global<_invalid_parameter_handler> __acrt_invalid_parameter_handler;
13
14
15
16 #if defined _M_X64 && !defined _UCRT_ENCLAVE_BUILD
17
capture_current_context(CONTEXT * const context_record)18 static void __cdecl capture_current_context(CONTEXT* const context_record) throw()
19 {
20 ULONG64 ControlPc;
21 ULONG64 EstablisherFrame;
22 ULONG64 ImageBase;
23 PRUNTIME_FUNCTION FunctionEntry;
24 PVOID HandlerData;
25
26 RtlCaptureContext(context_record);
27
28 ControlPc = context_record->Rip;
29 FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, nullptr);
30
31 if (FunctionEntry != nullptr)
32 {
33 RtlVirtualUnwind(
34 UNW_FLAG_NHANDLER,
35 ImageBase,
36 ControlPc,
37 FunctionEntry,
38 context_record,
39 &HandlerData,
40 &EstablisherFrame,
41 nullptr);
42 }
43 }
44
45 #endif // _M_X64 && !_UCRT_ENCLAVE_BUILD
46
47 #if defined _CRT_GLOBAL_STATE_ISOLATION
48
49 // The legacy Windows CRT (msvcrt) does not terminate the process when an
50 // invalid parameter is passed to a library function. Turning on this
51 // validation for Windows components would be a big app compat problem.
52 //
53 // For OS components the default behavior will be to ignore the invalid parameters
54 // and that is accomplished by providing an empty IPH.
invalid_parameter_handler_continue(wchar_t const * const,wchar_t const * const,wchar_t const * const,unsigned int,uintptr_t)55 static void __cdecl invalid_parameter_handler_continue(
56 wchar_t const * const, // pszExpression
57 wchar_t const * const, // pszFunction
58 wchar_t const * const, // pszFile
59 unsigned int, // nLine
60 uintptr_t // pReserved
61 ) throw()
62 {
63 }
64
65 #endif
66
__acrt_initialize_invalid_parameter_handler(void * const encoded_null)67 extern "C" void __cdecl __acrt_initialize_invalid_parameter_handler(void* const encoded_null)
68 {
69 #if defined _CRT_GLOBAL_STATE_ISOLATION
70 const _invalid_parameter_handler encoded_os_iph = __crt_fast_encode_pointer(invalid_parameter_handler_continue);
71 #endif
72 const _invalid_parameter_handler iph[] =
73 {
74 reinterpret_cast<_invalid_parameter_handler>(encoded_null)
75 #if defined _CRT_GLOBAL_STATE_ISOLATION
76 ,encoded_os_iph
77 #endif
78 };
79
80 __acrt_invalid_parameter_handler.initialize_from_array(iph);
81 }
82
83
84
85 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
86 //
87 // _invalid_parameter
88 //
89 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
_invalid_parameter_internal(wchar_t const * const expression,wchar_t const * const function_name,wchar_t const * const file_name,unsigned int const line_number,uintptr_t const reserved,__crt_cached_ptd_host & ptd)90 extern "C" void __cdecl _invalid_parameter_internal(
91 wchar_t const* const expression,
92 wchar_t const* const function_name,
93 wchar_t const* const file_name,
94 unsigned int const line_number,
95 uintptr_t const reserved,
96 __crt_cached_ptd_host& ptd
97 )
98 {
99 __acrt_ptd * const raw_ptd = ptd.get_raw_ptd_noexit();
100 if (raw_ptd && raw_ptd->_thread_local_iph)
101 {
102 raw_ptd->_thread_local_iph(expression, function_name, file_name, line_number, reserved);
103 return;
104 }
105
106 _invalid_parameter_handler const global_handler = __crt_fast_decode_pointer(__acrt_invalid_parameter_handler.value(ptd));
107 if (global_handler)
108 {
109 global_handler(expression, function_name, file_name, line_number, reserved);
110 return;
111 }
112
113 _invoke_watson(expression, function_name, file_name, line_number, reserved);
114 }
115
_invalid_parameter(wchar_t const * const expression,wchar_t const * const function_name,wchar_t const * const file_name,unsigned int const line_number,uintptr_t const reserved)116 extern "C" void __cdecl _invalid_parameter(
117 wchar_t const* const expression,
118 wchar_t const* const function_name,
119 wchar_t const* const file_name,
120 unsigned int const line_number,
121 uintptr_t const reserved
122 )
123 {
124 __crt_cached_ptd_host ptd;
125 return _invalid_parameter_internal(expression, function_name, file_name, line_number, reserved, ptd);
126 }
127
_invalid_parameter_noinfo()128 extern "C" void __cdecl _invalid_parameter_noinfo()
129 {
130 _invalid_parameter(nullptr, nullptr, nullptr, 0, 0);
131 }
132
133 // This is used by inline code in the C++ Standard Library and the SafeInt
134 // library. Because it is __declspec(noreturn), the compiler can better
135 // optimize use of the invalid parameter handler for inline code.
_invalid_parameter_noinfo_noreturn()136 extern "C" __declspec(noreturn) void __cdecl _invalid_parameter_noinfo_noreturn()
137 {
138 _invalid_parameter(nullptr, nullptr, nullptr, 0, 0);
139 _invoke_watson (nullptr, nullptr, nullptr, 0, 0);
140 }
141
142
143
144 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
145 //
146 // _invoke_watson
147 //
148 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
149 #if (defined _M_IX86 || defined _M_X64) && !defined _UCRT_ENCLAVE_BUILD
150
__acrt_call_reportfault(int const debugger_hook_code,DWORD const _exception_code,DWORD const _exception_flags)151 extern "C" void __cdecl __acrt_call_reportfault(
152 int const debugger_hook_code,
153 DWORD const _exception_code,
154 DWORD const _exception_flags
155 )
156 {
157 // Notify the debugger if attached.
158 if (debugger_hook_code != _CRT_DEBUGGER_IGNORE)
159 {
160 _CRT_DEBUGGER_HOOK(debugger_hook_code);
161 }
162
163 // Fake an exception to call report fault:
164 EXCEPTION_RECORD ExceptionRecord{};
165 CONTEXT ContextRecord{};
166 EXCEPTION_POINTERS ExceptionPointers = {&ExceptionRecord, &ContextRecord};
167
168 #ifdef _M_IX86
169 #if defined(__GNUC__) || defined(__clang__)
170 __asm__ __volatile__(
171 "movl %%eax, %[CxEax]\n\t"
172 "movl %%ecx, %[CxEcx]\n\t"
173 "movl %%edx, %[CxEdx]\n\t"
174 "movl %%ebx, %[CxEbx]\n\t"
175 "movl %%esi, %[CxEsi]\n\t"
176 "movl %%edi, %[CxEdi]\n\t"
177 : [CxEax] "=m" (ContextRecord.Eax),
178 [CxEcx] "=m" (ContextRecord.Ecx),
179 [CxEdx] "=m" (ContextRecord.Edx),
180 [CxEbx] "=m" (ContextRecord.Ebx),
181 [CxEsi] "=m" (ContextRecord.Esi),
182 [CxEdi] "=m" (ContextRecord.Edi));
183 __asm__ __volatile__(
184 "movw %%ss, %[CxSegSs]\n\t"
185 "movw %%cs, %[CxSegCs]\n\t"
186 "movw %%ds, %[CxSegDs]\n\t"
187 "movw %%es, %[CxSegEs]\n\t"
188 "movw %%fs, %[CxSegFs]\n\t"
189 "movw %%gs, %[CxSegGs]\n\t"
190 : [CxSegSs] "=m" (ContextRecord.SegSs),
191 [CxSegCs] "=m" (ContextRecord.SegCs),
192 [CxSegDs] "=m" (ContextRecord.SegDs),
193 [CxSegEs] "=m" (ContextRecord.SegEs),
194 [CxSegFs] "=m" (ContextRecord.SegFs),
195 [CxSegGs] "=m" (ContextRecord.SegGs));
196 __asm__ __volatile__(
197 "pushfl\n\t"
198 "popl %[CxEFlags]\n\t"
199 : [CxEFlags] "=m" (ContextRecord.EFlags));
200 #else // ^^^ __GNUC__ ^^^ // vvv !__GNUC__ vvv //
201 __asm
202 {
203 mov dword ptr [ContextRecord.Eax ], eax
204 mov dword ptr [ContextRecord.Ecx ], ecx
205 mov dword ptr [ContextRecord.Edx ], edx
206 mov dword ptr [ContextRecord.Ebx ], ebx
207 mov dword ptr [ContextRecord.Esi ], esi
208 mov dword ptr [ContextRecord.Edi ], edi
209 mov word ptr [ContextRecord.SegSs], ss
210 mov word ptr [ContextRecord.SegCs], cs
211 mov word ptr [ContextRecord.SegDs], ds
212 mov word ptr [ContextRecord.SegEs], es
213 mov word ptr [ContextRecord.SegFs], fs
214 mov word ptr [ContextRecord.SegGs], gs
215 pushfd
216 pop [ContextRecord.EFlags]
217 }
218 #endif // !__GNUC__
219
220 ContextRecord.ContextFlags = CONTEXT_CONTROL;
221
222 ContextRecord.Eip = (ULONG)_ReturnAddress();
223 ContextRecord.Esp = (ULONG)_AddressOfReturnAddress();
224 ContextRecord.Ebp = *((ULONG *)_AddressOfReturnAddress()-1);
225
226 #else // ^^^ _M_IX86 ^^^ // vvv _M_X64 vvv //
227
228 capture_current_context(&ContextRecord);
229 ContextRecord.Rip = (ULONGLONG)_ReturnAddress();
230 ContextRecord.Rsp = (ULONGLONG)_AddressOfReturnAddress()+8;
231
232 #endif // _M_X64
233
234 ExceptionRecord.ExceptionCode = _exception_code;
235 ExceptionRecord.ExceptionFlags = _exception_flags;
236 ExceptionRecord.ExceptionAddress = _ReturnAddress();
237
238 BOOL const was_debugger_present = IsDebuggerPresent();
239
240 // Raises an exception that bypasses all exception handlers:
241 #pragma warning(suppress:__WARNING_SETUNHANDLEDEXCEPTIONFILTER_USE) // 28725 Use Watson instead of this SetUnhandledExceptionFilter.
242 SetUnhandledExceptionFilter(nullptr);
243 DWORD const handler_result = UnhandledExceptionFilter(&ExceptionPointers);
244
245 // If no handler was found and no debugger was previously attached, then
246 // execution must stop into the debugger hook:
247 if (handler_result == EXCEPTION_CONTINUE_SEARCH && !was_debugger_present && debugger_hook_code != _CRT_DEBUGGER_IGNORE)
248 {
249 _CRT_DEBUGGER_HOOK(debugger_hook_code);
250 }
251 }
252
_invoke_watson(wchar_t const * const expression,wchar_t const * const function_name,wchar_t const * const file_name,unsigned int const line_number,uintptr_t const reserved)253 extern "C" __declspec(noreturn) void __cdecl _invoke_watson(
254 wchar_t const* const expression,
255 wchar_t const* const function_name,
256 wchar_t const* const file_name,
257 unsigned int const line_number,
258 uintptr_t const reserved
259 )
260 {
261 UNREFERENCED_PARAMETER(expression );
262 UNREFERENCED_PARAMETER(function_name);
263 UNREFERENCED_PARAMETER(file_name );
264 UNREFERENCED_PARAMETER(line_number );
265 UNREFERENCED_PARAMETER(reserved );
266
267 if (IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE))
268 {
269 __fastfail(FAST_FAIL_INVALID_ARG);
270 }
271
272 // Otherwise, raise a fast-fail exception and termintae the process:
273 __acrt_call_reportfault(
274 _CRT_DEBUGGER_INVALIDPARAMETER,
275 STATUS_INVALID_CRUNTIME_PARAMETER,
276 EXCEPTION_NONCONTINUABLE);
277
278 TerminateProcess(GetCurrentProcess(), STATUS_INVALID_CRUNTIME_PARAMETER);
279 UNREACHABLE;
280 }
281
282 #else // ^^^ (_M_IX86 || _M_X64) && !_UCRT_ENCLAVE_BUILD ^^^ // vvv Newer Architectures vvv //
283
_invoke_watson(wchar_t const * const expression,wchar_t const * const function_name,wchar_t const * const file_name,unsigned int const line_number,uintptr_t const reserved)284 extern "C" __declspec(noreturn) void __cdecl _invoke_watson(
285 wchar_t const* const expression,
286 wchar_t const* const function_name,
287 wchar_t const* const file_name,
288 unsigned int const line_number,
289 uintptr_t const reserved
290 )
291 {
292 UNREFERENCED_PARAMETER(expression );
293 UNREFERENCED_PARAMETER(function_name);
294 UNREFERENCED_PARAMETER(file_name );
295 UNREFERENCED_PARAMETER(line_number );
296 UNREFERENCED_PARAMETER(reserved );
297
298 __fastfail(FAST_FAIL_INVALID_ARG);
299 }
300
301 #endif
302
303
304
305 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
306 //
307 // Handler Accessors
308 //
309 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
_set_invalid_parameter_handler(_invalid_parameter_handler const new_handler)310 extern "C" _invalid_parameter_handler __cdecl _set_invalid_parameter_handler(_invalid_parameter_handler const new_handler)
311 {
312 _invalid_parameter_handler const old_handler = __crt_fast_decode_pointer(__acrt_invalid_parameter_handler.value());
313 __acrt_invalid_parameter_handler.value() = __crt_fast_encode_pointer(new_handler);
314 return old_handler;
315 }
316
_get_invalid_parameter_handler()317 extern "C" _invalid_parameter_handler __cdecl _get_invalid_parameter_handler()
318 {
319 return __crt_fast_decode_pointer(__acrt_invalid_parameter_handler.value());
320 }
321
322
323
_set_thread_local_invalid_parameter_handler(_invalid_parameter_handler const new_handler)324 extern "C" _invalid_parameter_handler __cdecl _set_thread_local_invalid_parameter_handler(_invalid_parameter_handler const new_handler)
325 {
326 __acrt_ptd* const ptd = __acrt_getptd();
327
328 _invalid_parameter_handler const old_handler = ptd->_thread_local_iph;
329 ptd->_thread_local_iph = new_handler;
330 return old_handler;
331 }
332
_get_thread_local_invalid_parameter_handler()333 extern "C" _invalid_parameter_handler __cdecl _get_thread_local_invalid_parameter_handler()
334 {
335 __acrt_ptd* const ptd = __acrt_getptd_noexit();
336 if (!ptd)
337 {
338 return nullptr;
339 }
340
341 return ptd->_thread_local_iph;
342 }
343