mirror of
https://github.com/Chuyu-Team/VC-LTL5.git
synced 2026-10-21 07:55:48 +08:00
447 lines
14 KiB
C++
447 lines
14 KiB
C++
/***
|
|
*ehhelpers.cpp - Some target-independent helper routines used by the EH frame handler.
|
|
*
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
*
|
|
****/
|
|
|
|
#include <eh.h> // User-visible routines for eh
|
|
#include <ehassert.h> // This project's versions of standard assert macros
|
|
#include <ehdata.h> // Declarations of all types used for EH
|
|
#include <ehdata4.h>
|
|
#include <ehhooks.h> // Declarations of hook variables and callbacks
|
|
#include <trnsctrl.h> // Routines to handle transfer of control (trnsctrl.asm)
|
|
#include <vcruntime_exception.h>
|
|
#include <vcruntime_typeinfo.h>
|
|
|
|
#include <Unknwn.h>
|
|
#include <Windows.h>
|
|
|
|
#include "ehhelpers.h"
|
|
#include "framework.h"
|
|
|
|
// If we call DestructExceptionObject directly from C_Specific_Handler/
|
|
// _except_handler3, then this obj file will be pulled in by the linker
|
|
// even in programs which do not have C++ exceptions. So we call it using a
|
|
// function pointer _pDestructExceptionObject which gets initialized to 0 by
|
|
// default. If C++ exceptions are present, this file will be pulled in naturally
|
|
// and _pDestructExceptionObject will point to __DestructExceptionObject.
|
|
|
|
#if 0
|
|
extern "C" void (__cdecl * const _pDestructExceptionObject)(EHExceptionRecord *,BOOLEAN)
|
|
= &__DestructExceptionObject;
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// __AdjustPointer - Adjust the pointer to the exception object to a pointer to a
|
|
// base instance.
|
|
//
|
|
// Output:
|
|
// The address point of the base.
|
|
//
|
|
// Side-effects:
|
|
// NONE.
|
|
|
|
#if WindowsTargetPlatformMinVersion < WindowsTargetPlatformWindowsBlue
|
|
extern "C" _VCRTIMP void *__AdjustPointer(
|
|
void *pThis, // Address point of exception object
|
|
const PMD& pmd // Generalized pointer-to-member
|
|
// descriptor
|
|
) {
|
|
char *pRet = (char *)pThis + pmd.mdisp;
|
|
|
|
if (pmd.pdisp >= 0) {
|
|
pRet += *(__int32 *)((char *)*(ptrdiff_t *)((char *)pThis + pmd.pdisp)
|
|
#if defined(_WIN64)
|
|
+ (unsigned __int64)pmd.vdisp
|
|
#else
|
|
+ pmd.vdisp
|
|
#endif
|
|
);
|
|
pRet += pmd.pdisp;
|
|
}
|
|
|
|
return pRet;
|
|
}
|
|
|
|
_LCRT_DEFINE_IAT_SYMBOL(__AdjustPointer);
|
|
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// __GetPlatformExceptionInfo - Get Platform Exception extra information from current exception
|
|
//
|
|
// Output:
|
|
// The address of WINRTEXCEPTIONINFO structure
|
|
//
|
|
// Side-effects:
|
|
// NONE.
|
|
#if WindowsTargetPlatformMinVersion < __MakeVersion(10, 0, 10240)
|
|
extern "C" _VCRTIMP void * __GetPlatformExceptionInfo(
|
|
int *pIsBadAlloc
|
|
) {
|
|
*pIsBadAlloc = 0;
|
|
EHExceptionRecord *pExcept = _pCurrentException;
|
|
if (pExcept)
|
|
{
|
|
ThrowInfo* pTI = PER_PTHROW(pExcept);
|
|
if (pTI)
|
|
{
|
|
if (THROW_ISWINRT( (*pTI) ) )
|
|
{
|
|
ULONG_PTR *exceptionInfoPointer = *reinterpret_cast<ULONG_PTR**>(PER_PEXCEPTOBJ(pExcept));
|
|
exceptionInfoPointer--;
|
|
return reinterpret_cast<void*>(*exceptionInfoPointer);
|
|
}
|
|
else
|
|
{
|
|
_EXCEPTION_POINTERS exceptionPointers;
|
|
exceptionPointers.ExceptionRecord = reinterpret_cast<PEXCEPTION_RECORD>(pExcept);
|
|
exceptionPointers.ContextRecord = nullptr;
|
|
|
|
*pIsBadAlloc = _is_exception_typeof(typeid(std::bad_alloc), &exceptionPointers);
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
_LCRT_DEFINE_IAT_SYMBOL(__GetPlatformExceptionInfo);
|
|
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// __current_exception(), __current_exception_context(), __processing_throw()
|
|
// - Accessors for the per-thread exception state, used
|
|
// by the managed EH implementation, exception_ptr, etc.
|
|
//
|
|
|
|
// Don't define these "locally" for satellite DLL build, the satellite
|
|
// needs to call these from the base vcruntime to infer the location of the PTD
|
|
#if !defined _VCRT_SAT_1
|
|
#if WindowsTargetPlatformMinVersion < __MakeVersion(10, 0, 10240)
|
|
extern "C" void** __cdecl __current_exception()
|
|
{
|
|
//return &RENAME_BASE_PTD(__vcrt_getptd)()->_curexception;
|
|
|
|
auto ptd = __vcrt_getptd();
|
|
|
|
#if WindowsTargetPlatformMinVersion < __MakeVersion(6, 0, 6000)
|
|
const auto OSVersion = __LTL_GetOsMinVersion();
|
|
|
|
if (OSVersion < MakeMiniVersion(5, 1))
|
|
{
|
|
return &((_ptd_msvcrt_win2k*)ptd)->_curexception;
|
|
}
|
|
else if (OSVersion < MakeMiniVersion(6, 0))
|
|
{
|
|
return &((_ptd_msvcrt_winxp*)ptd)->_curexception;
|
|
}
|
|
#endif
|
|
//Win6
|
|
return &((_ptd_msvcrt_win6_shared*)ptd)->_curexception;
|
|
}
|
|
|
|
_LCRT_DEFINE_IAT_SYMBOL(__current_exception);
|
|
|
|
#endif
|
|
#endif
|
|
|
|
#if WindowsTargetPlatformMinVersion < __MakeVersion(10, 0, 10240)
|
|
extern "C" void** __cdecl __current_exception_context()
|
|
{
|
|
//return &RENAME_BASE_PTD(__vcrt_getptd)()->_curcontext;
|
|
auto ptd = __vcrt_getptd();
|
|
|
|
#if WindowsTargetPlatformMinVersion < __MakeVersion(6, 0, 6000)
|
|
const auto OSVersion = __LTL_GetOsMinVersion();
|
|
#endif
|
|
|
|
#if WindowsTargetPlatformMinVersion < __MakeVersion(5, 1, 2600)
|
|
if (OSVersion < MakeMiniVersion(5, 1))
|
|
{
|
|
return &((_ptd_msvcrt_win2k*)ptd)->_curcontext;
|
|
}
|
|
#endif
|
|
|
|
#if WindowsTargetPlatformMinVersion < __MakeVersion(6, 0, 6000)
|
|
if (OSVersion < MakeMiniVersion(6, 0))
|
|
{
|
|
return &((_ptd_msvcrt_winxp*)ptd)->_curcontext;
|
|
}
|
|
#endif
|
|
|
|
//Win6
|
|
return &((_ptd_msvcrt_win6_shared*)ptd)->_curcontext;
|
|
}
|
|
|
|
_LCRT_DEFINE_IAT_SYMBOL(__current_exception_context);
|
|
|
|
#endif
|
|
|
|
#if WindowsTargetPlatformMinVersion < __MakeVersion(10, 0, 10240)
|
|
extern "C" int* __cdecl __processing_throw()
|
|
{
|
|
//return &RENAME_BASE_PTD(__vcrt_getptd)()->_ProcessingThrow;
|
|
auto ptd = __vcrt_getptd();
|
|
|
|
#if WindowsTargetPlatformMinVersion < __MakeVersion(6, 0, 6000)
|
|
const auto OSVersion = __LTL_GetOsMinVersion();
|
|
#endif
|
|
|
|
#if WindowsTargetPlatformMinVersion < __MakeVersion(5, 1, 2600)
|
|
#error "尚未支持"
|
|
if (OSVersion < MakeMiniVersion(5, 1))
|
|
{
|
|
return &((_ptd_msvcrt_win2k*)ptd)->_ProcessingThrow;
|
|
}
|
|
#endif
|
|
|
|
#if WindowsTargetPlatformMinVersion < __MakeVersion(6, 0, 6000)
|
|
if (OSVersion < MakeMiniVersion(6, 0))
|
|
{
|
|
return &((_ptd_msvcrt_winxp*)ptd)->_ProcessingThrow;
|
|
}
|
|
#endif
|
|
|
|
//Win6
|
|
return &((_ptd_msvcrt_win6_shared*)ptd)->_ProcessingThrow;
|
|
}
|
|
|
|
_LCRT_DEFINE_IAT_SYMBOL(__processing_throw);
|
|
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// __FrameUnwindFilter - Allows possibility of continuing through SEH during
|
|
// unwind.
|
|
//
|
|
#if WindowsTargetPlatformMinVersion < __MakeVersion(10, 0, 10240)
|
|
extern "C" _VCRTIMP int __cdecl __FrameUnwindFilter(
|
|
EXCEPTION_POINTERS *pExPtrs
|
|
) {
|
|
EHExceptionRecord *pExcept = (EHExceptionRecord *)pExPtrs->ExceptionRecord;
|
|
|
|
switch (PER_CODE(pExcept)) {
|
|
case EH_EXCEPTION_NUMBER:
|
|
_pCurrentException = pExcept;
|
|
_pCurrentExContext = pExPtrs->ContextRecord;
|
|
terminate();
|
|
|
|
case MANAGED_EXCEPTION_CODE:
|
|
case MANAGED_EXCEPTION_CODE_V4:
|
|
/*
|
|
See VSW#544593 for more details. __ProcessingThrow is used to implement
|
|
std::uncaught_exception(). The interaction between C++, SEH and managed
|
|
exception wrt __ProcessingThrow is unspec'ed. From code inspection, it
|
|
looks like that __ProcessingThrow works ok with all C++ exceptions.
|
|
|
|
In this case, when we encounter a managed exception thrown from a destructor
|
|
during unwind, we choose to decrement the count. This means that the previous
|
|
C++ exception which incremented the count won't be considered any longer.
|
|
In fact, the managed exception will be thrown, and the native C++ one will
|
|
not have any possibility to be caught any longer.
|
|
|
|
We should revisit std::uncaught_exception() and SEH/managed exception in the
|
|
next version.
|
|
*/
|
|
if (__ProcessingThrow > 0)
|
|
{
|
|
--__ProcessingThrow;
|
|
}
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
|
|
default:
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
}
|
|
}
|
|
|
|
_LCRT_DEFINE_IAT_SYMBOL(__FrameUnwindFilter);
|
|
|
|
#endif
|
|
|
|
|
|
#if WindowsTargetPlatformMinVersion < __MakeVersion(10, 0, 10240)
|
|
|
|
PGETWINRT_OOM_EXCEPTION __WinRTOutOfMemoryExceptionCallback = nullptr;
|
|
|
|
extern "C" _VCRTIMP void __cdecl _SetWinRTOutOfMemoryExceptionCallback(PGETWINRT_OOM_EXCEPTION pCallback)
|
|
{
|
|
__WinRTOutOfMemoryExceptionCallback = pCallback;
|
|
}
|
|
|
|
_LCRT_DEFINE_IAT_SYMBOL(_SetWinRTOutOfMemoryExceptionCallback);
|
|
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
// __std_terminate: Helper function referenced by the front-end to assist in
|
|
// implementing noexcept. Noexcept termination semantics are generally handled
|
|
// by FindHandler() above, when we cross a function with the noexcept bit set
|
|
// in the xdata when looking for a handler. When noexcept functions are inlined,
|
|
// though, we may no longer cross a noexcept function boundary when searching for
|
|
// a handler. In this case the inlined code contains an EH state that will invoke
|
|
// this function should an exception occur.
|
|
#if 0
|
|
extern "C" __declspec(noreturn) void __cdecl __std_terminate()
|
|
{
|
|
terminate();
|
|
}
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// __DestructExceptionObject - Call the destructor (if any) of the original
|
|
// exception object.
|
|
//
|
|
// Returns: None.
|
|
//
|
|
// Side-effects:
|
|
// Original exception object is destructed.
|
|
//
|
|
// Notes:
|
|
// If destruction throws any exception, and we are destructing the exception
|
|
// object as a result of a new exception, we give up. If the destruction
|
|
// throws otherwise, we let it be.
|
|
|
|
#if 0
|
|
static DWORD _FilterSetCurrentException(EXCEPTION_POINTERS* pointers, BOOLEAN fThrowNotAllowed)
|
|
{
|
|
if (fThrowNotAllowed) {
|
|
const auto eRecord = reinterpret_cast<EHExceptionRecord*>(pointers->ExceptionRecord);
|
|
if (PER_IS_MSVC_EH(eRecord))
|
|
{
|
|
// Can't have new exceptions when we're unwinding due to another
|
|
// exception.
|
|
_pCurrentException = eRecord;
|
|
_pCurrentExContext = pointers->ContextRecord;
|
|
terminate();
|
|
}
|
|
}
|
|
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
}
|
|
|
|
extern "C" _VCRTIMP void __cdecl __DestructExceptionObject(
|
|
EHExceptionRecord *pExcept, // The original exception record
|
|
BOOLEAN fThrowNotAllowed // TRUE if destructor not allowed to
|
|
// throw
|
|
) {
|
|
// Ignore if not a C++ exception (since this is now called from
|
|
// _except_handler3)
|
|
if (pExcept == nullptr || !(PER_IS_MSVC_EH(pExcept)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
EHTRACE_FMT1("Destroying object @ 0x%p", PER_PEXCEPTOBJ(pExcept));
|
|
|
|
/*UNDONE:Is this _SYSCRT specific */
|
|
#pragma prefast(suppress:__WARNING_REDUNDANT_POINTER_TEST, "Current definition of PER_CODE ensures that pExcept cannot be nullptr")
|
|
if (PER_PTHROW(pExcept)) {
|
|
if (THROW_UNWINDFUNC(*PER_PTHROW(pExcept)) != 0) {
|
|
|
|
__try {
|
|
|
|
#if _EH_RELATIVE_TYPEINFO
|
|
_CallMemberFunction0(PER_PEXCEPTOBJ(pExcept),
|
|
THROW_UNWINDFUNC_IB(*PER_PTHROW(pExcept),(ptrdiff_t)PER_PTHROWIB(pExcept)));
|
|
#else
|
|
_CallMemberFunction0(PER_PEXCEPTOBJ(pExcept),
|
|
THROW_UNWINDFUNC(*PER_PTHROW(pExcept)));
|
|
#endif
|
|
|
|
} __except(_FilterSetCurrentException(GetExceptionInformation(), fThrowNotAllowed)) {}
|
|
}
|
|
else if (THROW_ISWINRT(*PER_PTHROW(pExcept))) {
|
|
// Release if WinRT reference type exception
|
|
IUnknown* const pUnknown = *static_cast<IUnknown**>(PER_PEXCEPTOBJ(pExcept));
|
|
if (pUnknown) {
|
|
pUnknown->Release();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// _IsExceptionObjectToBeDestroyed - Determine if an exception object is still
|
|
// in use by a more deeply nested catch frame, or if it unused and should be
|
|
// destroyed on exiting from the current catch block.
|
|
//
|
|
// Returns:
|
|
// TRUE if exception object not found and should be destroyed.
|
|
//
|
|
#if WindowsTargetPlatformMinVersion < __MakeVersion(10, 0, 10240)
|
|
extern "C" BOOL __cdecl _IsExceptionObjectToBeDestroyed(
|
|
PVOID pExceptionObject
|
|
) {
|
|
FRAMEINFO * pFrameInfo;
|
|
|
|
for (pFrameInfo = pFrameInfoChain; pFrameInfo; pFrameInfo = pFrameInfo->pNext ) {
|
|
if (pFrameInfo->pExceptionObject == pExceptionObject) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
_LCRT_DEFINE_IAT_SYMBOL(_IsExceptionObjectToBeDestroyed);
|
|
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
// _is_exception_typeof - checks if the thrown exception is the type, the caller
|
|
// has passed in.
|
|
//
|
|
#if WindowsTargetPlatformMinVersion < __MakeVersion(10, 0, 10240)
|
|
extern "C" _VCRTIMP int __cdecl _is_exception_typeof(const type_info & type, struct _EXCEPTION_POINTERS * ep)
|
|
{
|
|
_VCRT_VERIFY(ep);
|
|
|
|
EHExceptionRecord *pExcept = (EHExceptionRecord *)ep->ExceptionRecord;
|
|
|
|
// Is this our Exception?
|
|
_VCRT_VERIFY(pExcept && PER_IS_MSVC_EH(pExcept));
|
|
|
|
#if _EH_RELATIVE_TYPEINFO
|
|
__int32 const *ppCatchable;
|
|
ptrdiff_t imgBase = (ptrdiff_t)pExcept->params.pThrowImageBase;
|
|
ppCatchable = THROW_CTLIST_IB(*PER_PTHROW(pExcept), imgBase );
|
|
int catchables = THROW_COUNT_IB(*PER_PTHROW(pExcept), imgBase );
|
|
#else
|
|
CatchableType * const *ppCatchable;
|
|
ppCatchable = THROW_CTLIST(*PER_PTHROW(pExcept));
|
|
int catchables = THROW_COUNT(*PER_PTHROW(pExcept));
|
|
#endif
|
|
|
|
CatchableType *pCatchable;
|
|
|
|
// Scan all types that thrown object can be converted to.
|
|
for (; catchables > 0; catchables--, ppCatchable++)
|
|
{
|
|
#if _EH_RELATIVE_TYPEINFO
|
|
pCatchable = (CatchableType *)(imgBase + *ppCatchable);
|
|
if(strcmp(type.raw_name(), CT_NAME_IB(*pCatchable, imgBase)) == 0)
|
|
#else
|
|
pCatchable = *ppCatchable;
|
|
if(strcmp(type.raw_name(), CT_NAME(*pCatchable)) == 0)
|
|
#endif
|
|
{
|
|
// Found a Match.
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
_LCRT_DEFINE_IAT_SYMBOL(_is_exception_typeof);
|
|
|
|
#endif |