/*** *invarg.c - stub for invalid argument handler * * Copyright (c) Microsoft Corporation. All rights reserved. * *Purpose: * defines _invalidarg() and _set_invalid_parameter_handler() * *Revision History: * 05-01-03 SSM Module created * 04-10-04 AJS Builds as C++; unsigned short overload of _invalid_parameter for use by managed code * 04-11-04 AC Use EncodePointer to store the user handler * VSW#225573 * 10-29-04 DJT Added functions for secure pointers for use throughout the CRT * 11-02-04 AC Call unhandled exception filter directly to invoke watson * VSW#320460 * 01-09-05 AC Moved initialization of __pInvalidArgHandler in .CRT$XIC * VSW#422266 * 01-12-05 DJT Use OS-encoded global function pointers * 03-24-05 AC Added encode/decode function which do not take the loader lock * VSW#473724 * 03-23-05 MSL Review comment cleanup * 03-31-05 PAL Don't invoke _CRT_DEBUGGER_HOOK on invalid parameter if the * user has defined a handler. * 05-06-05 AC Add _invalid_parameter_noinfo, to have better code generation with Secure SCL * 05-25-05 AI Call the debugger hook, inside __invoke_watson, if the exception search filter * found no handler and if there was no debugger previously attached. VSW#495287 * *******************************************************************************/ #include #ifndef _WIN32_WCE #include #endif /* _WIN32_WCE */ #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif void * _ReturnAddress(void); #pragma intrinsic(_ReturnAddress) #ifdef _X86_ void * _AddressOfReturnAddress(void); #pragma intrinsic(_AddressOfReturnAddress) #endif #ifndef _WIN32_WCE /* global variable which stores the user handler */ _invalid_parameter_handler __pInvalidArgHandler; extern "C" void _initp_misc_invarg(void* enull) { __pInvalidArgHandler = (_invalid_parameter_handler) enull; } #endif /* _WIN32_WCE */ // just the declaration of the _invalid_parameter here, WinCE 6.0 requires it to be moved to another file. _CRTIMP void __cdecl _invalid_parameter( const wchar_t *pszExpression, const wchar_t *pszFunction, const wchar_t *pszFile, unsigned int nLine, uintptr_t pReserved ); #ifndef _DEBUG /* wrapper which passes no debug info; not available in debug * used in inline code: we don't pass the null params, so we gain some * speed and space in code generation */ _CRTIMP void __cdecl _invalid_parameter_noinfo(void) { _invalid_parameter(NULL, NULL, NULL, 0, 0); } #endif _CRTIMP void __cdecl _invoke_watson( const wchar_t *pszExpression, const wchar_t *pszFunction, const wchar_t *pszFile, unsigned int nLine, uintptr_t pReserved ) { #ifndef _WIN32_WCE /* Fake an exception to call reportfault. */ EXCEPTION_RECORD ExceptionRecord; CONTEXT ContextRecord; EXCEPTION_POINTERS ExceptionPointers; BOOL wasDebuggerPresent = FALSE; DWORD ret = 0; #endif /* _WIN32_WCE */ (pszExpression); (pszFunction); (pszFile); (nLine); (pReserved); #ifndef _WIN32_WCE #ifdef _X86_ __asm { mov dword ptr [ContextRecord.Eax], eax mov dword ptr [ContextRecord.Ecx], ecx mov dword ptr [ContextRecord.Edx], edx mov dword ptr [ContextRecord.Ebx], ebx mov dword ptr [ContextRecord.Esi], esi mov dword ptr [ContextRecord.Edi], edi mov word ptr [ContextRecord.SegSs], ss mov word ptr [ContextRecord.SegCs], cs mov word ptr [ContextRecord.SegDs], ds mov word ptr [ContextRecord.SegEs], es mov word ptr [ContextRecord.SegFs], fs mov word ptr [ContextRecord.SegGs], gs pushfd pop [ContextRecord.EFlags] } ContextRecord.ContextFlags = CONTEXT_CONTROL; #pragma warning(push) #pragma warning(disable:4311) ContextRecord.Eip = (ULONG)_ReturnAddress(); ContextRecord.Esp = (ULONG)_AddressOfReturnAddress(); #pragma warning(pop) ContextRecord.Ebp = *((ULONG *)_AddressOfReturnAddress()-1); #elif defined(_IA64_) || defined(_AMD64_) /* Need to fill up the Context in IA64 and AMD64. */ RtlCaptureContext(&ContextRecord); #else ZeroMemory(&ContextRecord, sizeof(ContextRecord)); #endif ZeroMemory(&ExceptionRecord, sizeof(ExceptionRecord)); ExceptionRecord.ExceptionCode = STATUS_INVALID_PARAMETER; ExceptionRecord.ExceptionAddress = _ReturnAddress(); ExceptionPointers.ExceptionRecord = &ExceptionRecord; ExceptionPointers.ContextRecord = &ContextRecord; wasDebuggerPresent = IsDebuggerPresent(); /* Make sure any filter already in place is deleted. */ SetUnhandledExceptionFilter(NULL); ret = UnhandledExceptionFilter(&ExceptionPointers); // if no handler found and no debugger previously attached // the execution must stop into the debugger hook. if (ret == EXCEPTION_CONTINUE_SEARCH && !wasDebuggerPresent) { _CRT_DEBUGGER_HOOK(_CRT_DEBUGGER_INVALIDPARAMETER); } TerminateProcess(GetCurrentProcess(), STATUS_INVALID_PARAMETER); #else RaiseException(STATUS_INVALID_PARAMETER, 0, 0, NULL); #endif /* _WIN32_WCE */ } #ifndef _WIN32_WCE /*** *void _set_invalid_parameter_handler(void) - * *Purpose: * Establish a handler to be called when a CRT detects a invalid parameter * * This function is not thread-safe * *Entry: * New handler * *Exit: * Old handler * *Exceptions: * *******************************************************************************/ _CRTIMP _invalid_parameter_handler __cdecl _set_invalid_parameter_handler( _invalid_parameter_handler pNew ) { _invalid_parameter_handler pOld = NULL; pOld = __pInvalidArgHandler; pOld = (_invalid_parameter_handler) _decode_pointer((PVOID)pOld); pNew = (_invalid_parameter_handler) _encode_pointer((PVOID)pNew); __pInvalidArgHandler = pNew; return pOld; } _CRTIMP _invalid_parameter_handler __cdecl _get_invalid_parameter_handler( ) { _invalid_parameter_handler pOld = NULL; pOld = __pInvalidArgHandler; pOld = (_invalid_parameter_handler) _decode_pointer((PVOID)pOld); return pOld; } #endif /* _WIN32_WCE */ #ifdef __cplusplus } #endif #ifndef _WIN32_WCE #ifdef __cplusplus #if defined(_NATIVE_WCHAR_T_DEFINED) // just the declaration of the _invalid_parameter here, WinCE 6.0 requires it to be moved to another file. extern "C++" _CRTIMP void __cdecl _invalid_parameter( const unsigned short * pszExpression, const unsigned short * pszFunction, const unsigned short * pszFile, unsigned int nLine, uintptr_t pReserved ); extern "C++" void __cdecl _invoke_watson( const unsigned short * pszExpression, const unsigned short * pszFunction, const unsigned short * pszFile, unsigned int nLine, uintptr_t pReserved ) { _invoke_watson( reinterpret_cast(pszExpression), reinterpret_cast(pszFunction), reinterpret_cast(pszFile), nLine, pReserved ); } #endif // defined(_NATIVE_WCHAR_T_DEFINED) #endif // __cplusplus #endif /* _WIN32_WCE */