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 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. 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 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 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 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 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 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. 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 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 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 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 //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 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 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 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 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