diff options
-rw-r--r-- | src/inc/corinfo.h | 22 | ||||
-rw-r--r-- | src/jit/compiler.h | 10 | ||||
-rw-r--r-- | src/jit/ee_il_dll.cpp | 109 | ||||
-rw-r--r-- | src/jit/importer.cpp | 96 | ||||
-rw-r--r-- | src/vm/jitinterface.cpp | 118 | ||||
-rw-r--r-- | src/vm/jitinterface.h | 4 | ||||
-rw-r--r-- | src/zap/zapinfo.cpp | 6 | ||||
-rw-r--r-- | src/zap/zapinfo.h | 1 |
8 files changed, 273 insertions, 93 deletions
diff --git a/src/inc/corinfo.h b/src/inc/corinfo.h index fb839996c0..8978b951a5 100644 --- a/src/inc/corinfo.h +++ b/src/inc/corinfo.h @@ -231,11 +231,11 @@ TODO: Talk about initializing strutures before use #if COR_JIT_EE_VERSION > 460 // Update this one -SELECTANY const GUID JITEEVersionIdentifier = { /* 27626524-7315-4ed0-b74e-a0e4579883bb */ - 0x27626524, - 0x7315, - 0x4ed0, - { 0xb7, 0x4e, 0xa0, 0xe4, 0x57, 0x98, 0x83, 0xbb } +SELECTANY const GUID JITEEVersionIdentifier = { /* 8c8e61ca-2b88-4bc5-b03f-d390acdc7fc3 */ + 0x8c8e61ca, + 0x2b88, + 0x4bc5, + { 0xb0, 0x3f, 0xd3, 0x90, 0xac, 0xdc, 0x7f, 0xc3 } }; #else @@ -2153,9 +2153,19 @@ public: // /**********************************************************************************/ - // Resolve metadata token into runtime method handles. + // Resolve metadata token into runtime method handles. This function may not + // return normally (e.g. it may throw) if it encounters invalid metadata or other + // failures during token resolution. virtual void resolveToken(/* IN, OUT */ CORINFO_RESOLVED_TOKEN * pResolvedToken) = 0; +#if COR_JIT_EE_VERSION > 460 + // Attempt to resolve a metadata token into a runtime method handle. Returns true + // if resolution succeeded and false otherwise (e.g. if it encounters invalid metadata + // during token reoslution). This method should be used instead of `resolveToken` in + // situations that need to be resilient to invalid metadata. + virtual bool tryResolveToken(/* IN, OUT */ CORINFO_RESOLVED_TOKEN * pResolvedToken) = 0; +#endif + // Signature information about the call sig virtual void findSig ( CORINFO_MODULE_HANDLE module, /* IN */ diff --git a/src/jit/compiler.h b/src/jit/compiler.h index 2c094a33c8..4b6ee0ee27 100644 --- a/src/jit/compiler.h +++ b/src/jit/compiler.h @@ -59,6 +59,10 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #include "simd.h" +// This is only used locally in the JIT to indicate that +// a verification block should be inserted +#define SEH_VERIFICATION_EXCEPTION 0xe0564552 // VER + /***************************************************************************** * Forward declarations */ @@ -6450,6 +6454,8 @@ public : /*OUT*/ SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR* structPassInRegDescPtr); #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING + bool eeTryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken); + // Utility functions #if defined(DEBUG) @@ -8373,10 +8379,6 @@ public: // be used to call a member function. BOOL verTrackObjCtorInitState; - // Argument of ICorJitInfo::resolveToken. It is used to determine the handling - // of ICorJitInfo::resolveToken failure during verification. - CORINFO_RESOLVED_TOKEN * verResolveTokenInProgress; - void verInitBBEntryState(BasicBlock* block, EntryState* currentState); diff --git a/src/jit/ee_il_dll.cpp b/src/jit/ee_il_dll.cpp index d28335cde6..8193b1573b 100644 --- a/src/jit/ee_il_dll.cpp +++ b/src/jit/ee_il_dll.cpp @@ -18,6 +18,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #pragma hdrstop #endif #include "emit.h" +#include "corexcep.h" /*****************************************************************************/ @@ -1127,6 +1128,114 @@ void Compiler::eeGetSystemVAmd64PassStructInRegisterDescriptor(/*IN*/ CORINFO_C #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING +#if COR_JIT_EE_VERSION <= 460 + +// Validate the token to determine whether to turn the bad image format exception into +// verification failure (for backward compatibility) +static bool isValidTokenForTryResolveToken(ICorJitInfo* corInfo, CORINFO_RESOLVED_TOKEN* resolvedToken) +{ + if (!corInfo->isValidToken(resolvedToken->tokenScope, resolvedToken->token)) + return false; + + CorInfoTokenKind tokenType = resolvedToken->tokenType; + switch (TypeFromToken(resolvedToken->token)) + { + case mdtModuleRef: + case mdtTypeDef: + case mdtTypeRef: + case mdtTypeSpec: + if ((tokenType & CORINFO_TOKENKIND_Class) == 0) + return false; + break; + + case mdtMethodDef: + case mdtMethodSpec: + if ((tokenType & CORINFO_TOKENKIND_Method) == 0) + return false; + break; + + case mdtFieldDef: + if ((tokenType & CORINFO_TOKENKIND_Field) == 0) + return false; + break; + + case mdtMemberRef: + if ((tokenType & (CORINFO_TOKENKIND_Method | CORINFO_TOKENKIND_Field)) == 0) + return false; + break; + + default: + return false; + } + + return true; +} + +// This type encapsulates the information necessary for `TryResolveTokenFilter` and +// `eeTryResolveToken` below. +struct TryResolveTokenFilterParam +{ + ICorJitInfo* m_corInfo; + CORINFO_RESOLVED_TOKEN* m_resolvedToken; + EXCEPTION_POINTERS m_exceptionPointers; + bool m_success; +}; + +LONG TryResolveTokenFilter(struct _EXCEPTION_POINTERS* exceptionPointers, void* theParam) +{ + assert(exceptionPointers->ExceptionRecord->ExceptionCode != SEH_VERIFICATION_EXCEPTION); + + // Backward compatibility: Convert bad image format exceptions thrown by the EE while resolving token to verification exceptions + // if we are verifying. Verification exceptions will cause the JIT of the basic block to fail, but the JITing of the whole method + // is still going to succeed. This is done for backward compatibility only. Ideally, we would always treat bad tokens in the IL + // stream as fatal errors. + if (exceptionPointers->ExceptionRecord->ExceptionCode == EXCEPTION_COMPLUS) + { + auto* param = reinterpret_cast<TryResolveTokenFilterParam*>(theParam); + if (!isValidTokenForTryResolveToken(param->m_corInfo, param->m_resolvedToken)) + { + param->m_exceptionPointers = *exceptionPointers; + return param->m_corInfo->FilterException(exceptionPointers); + } + } + + return EXCEPTION_CONTINUE_SEARCH; +} + +bool Compiler::eeTryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken) +{ + TryResolveTokenFilterParam param; + param.m_corInfo = info.compCompHnd; + param.m_resolvedToken = resolvedToken; + param.m_success = true; + + PAL_TRY(TryResolveTokenFilterParam*, pParam, ¶m) + { + pParam->m_corInfo->resolveToken(pParam->m_resolvedToken); + } + PAL_EXCEPT_FILTER(TryResolveTokenFilter) + { + if (param.m_exceptionPointers.ExceptionRecord->ExceptionCode == EXCEPTION_COMPLUS) + { + param.m_corInfo->HandleException(¶m.m_exceptionPointers); + } + + param.m_success = false; + } + PAL_ENDTRY + + return param.m_success; +} + +#else // CORJIT_EE_VER <= 460 + +bool Compiler::eeTryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken) +{ + return info.compCompHnd->tryResolveToken(resolvedToken); +} + +#endif // CORJIT_EE_VER > 460 + /***************************************************************************** * * Utility functions diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp index dea7a6ced3..03957eec0c 100644 --- a/src/jit/importer.cpp +++ b/src/jit/importer.cpp @@ -20,10 +20,6 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #include "corexcep.h" -// This is only used locally in the JIT to indicate that -// a verification block should be inserted -#define SEH_VERIFICATION_EXCEPTION 0xe0564552 // VER - #define Verify(cond, msg) \ do { \ if (!(cond)) { \ @@ -267,9 +263,14 @@ void Compiler::impResolveToken(const BYTE* addr, CORINFO_RESOLVED_TOKEN * pResol pResolvedToken->token = getU4LittleEndian(addr); pResolvedToken->tokenType = kind; - verResolveTokenInProgress = pResolvedToken; - info.compCompHnd->resolveToken(pResolvedToken); - verResolveTokenInProgress = NULL; + if (!tiVerificationNeeded) + { + info.compCompHnd->resolveToken(pResolvedToken); + } + else + { + Verify(eeTryResolveToken(pResolvedToken), "Token resolution failed"); + } } /***************************************************************************** @@ -14005,80 +14006,11 @@ void Compiler::impReimportMarkSuccessors(BasicBlock * block) * from it). */ -struct FilterVerificationExceptionsParam -{ - Compiler *pThis; - BasicBlock *block; - EXCEPTION_POINTERS exceptionPointers; -}; - -// -// Validate the token to determine whether to turn the bad image format exception into -// verification failure (for backward compatibility) -// -static bool verIsValidToken(COMP_HANDLE compCompHnd, CORINFO_RESOLVED_TOKEN * pResolvedToken) -{ - if (!compCompHnd->isValidToken(pResolvedToken->tokenScope, pResolvedToken->token)) - return FALSE; - - CorInfoTokenKind tokenType = pResolvedToken->tokenType; - - switch (TypeFromToken(pResolvedToken->token)) - { - case mdtModuleRef: - case mdtTypeDef: - case mdtTypeRef: - case mdtTypeSpec: - if ((tokenType & CORINFO_TOKENKIND_Class) == 0) - return FALSE; - break; - - case mdtMethodDef: - case mdtMethodSpec: - if ((tokenType & CORINFO_TOKENKIND_Method) == 0) - return FALSE; - break; - - case mdtFieldDef: - if ((tokenType & CORINFO_TOKENKIND_Field) == 0) - return FALSE; - break; - - case mdtMemberRef: - if ((tokenType & (CORINFO_TOKENKIND_Method | CORINFO_TOKENKIND_Field)) == 0) - return FALSE; - break; - - default: - return FALSE; - } - - return TRUE; -} - LONG FilterVerificationExceptions(PEXCEPTION_POINTERS pExceptionPointers, LPVOID lpvParam) { - FilterVerificationExceptionsParam *pFVEParam = - (FilterVerificationExceptionsParam *)lpvParam; - pFVEParam->exceptionPointers = *pExceptionPointers; - if (pExceptionPointers->ExceptionRecord->ExceptionCode == SEH_VERIFICATION_EXCEPTION) - return EXCEPTION_EXECUTE_HANDLER; - - // Backward compability: Convert bad image format exceptions thrown by the EE while resolving token to verification exceptions - // if we are verifying. Verification exceptions will cause the JIT of the basic block to fail, but the JITing of the whole method - // is still going to succeed. This is done for backward compatibility only. Ideally, we would always treat bad tokens in the IL - // stream as fatal errors. - if (pExceptionPointers->ExceptionRecord->ExceptionCode == EXCEPTION_COMPLUS) { - Compiler * pThis = pFVEParam->pThis; - if (pThis->tiVerificationNeeded && pThis->verResolveTokenInProgress) - { - if (!verIsValidToken(pThis->info.compCompHnd, pThis->verResolveTokenInProgress)) - { - return pThis->info.compCompHnd->FilterException(pExceptionPointers); - } - } + return EXCEPTION_EXECUTE_HANDLER; } return EXCEPTION_CONTINUE_SEARCH; @@ -14262,13 +14194,16 @@ void Compiler::impImportBlock(BasicBlock *block) /* Now walk the code and import the IL into GenTrees */ + struct FilterVerificationExceptionsParam + { + Compiler *pThis; + BasicBlock *block; + }; FilterVerificationExceptionsParam param; param.pThis = this; param.block = block; - verResolveTokenInProgress = NULL; - PAL_TRY(FilterVerificationExceptionsParam *, pParam, ¶m) { /* @VERIFICATION : For now, the only state propagation from try @@ -14314,9 +14249,6 @@ void Compiler::impImportBlock(BasicBlock *block) } PAL_EXCEPT_FILTER(FilterVerificationExceptions) { - if (param.exceptionPointers.ExceptionRecord->ExceptionCode == EXCEPTION_COMPLUS) - param.pThis->info.compCompHnd->HandleException(¶m.exceptionPointers); - verHandleVerificationFailure(block DEBUGARG(false)); } PAL_ENDTRY diff --git a/src/vm/jitinterface.cpp b/src/vm/jitinterface.cpp index cf0e456140..e29d6aa671 100644 --- a/src/vm/jitinterface.cpp +++ b/src/vm/jitinterface.cpp @@ -1292,6 +1292,116 @@ void CEEInfo::resolveToken(/* IN, OUT */ CORINFO_RESOLVED_TOKEN * pResolvedToken } /*********************************************************************/ +struct TryResolveTokenFilterParam +{ + CEEInfo* m_this; + CORINFO_RESOLVED_TOKEN* m_resolvedToken; + EXCEPTION_POINTERS m_exceptionPointers; + bool m_success; +}; + +bool isValidTokenForTryResolveToken(CEEInfo* info, CORINFO_RESOLVED_TOKEN* resolvedToken) +{ + LIMITED_METHOD_CONTRACT; + + if (!info->isValidToken(resolvedToken->tokenScope, resolvedToken->token)) + { + return false; + } + + CorInfoTokenKind tokenType = resolvedToken->tokenType; + switch (TypeFromToken(resolvedToken->token)) + { + case mdtModuleRef: + case mdtTypeDef: + case mdtTypeRef: + case mdtTypeSpec: + if ((tokenType & CORINFO_TOKENKIND_Class) == 0) + return false; + break; + + case mdtMethodDef: + case mdtMethodSpec: + if ((tokenType & CORINFO_TOKENKIND_Method) == 0) + return false; + break; + + case mdtFieldDef: + if ((tokenType & CORINFO_TOKENKIND_Field) == 0) + return false; + break; + + case mdtMemberRef: + if ((tokenType & (CORINFO_TOKENKIND_Method | CORINFO_TOKENKIND_Field)) == 0) + return false; + break; + + default: + return false; + } + + return true; +} + +LONG EEFilterException(struct _EXCEPTION_POINTERS* exceptionPointers, void* unused); + +LONG TryResolveTokenFilter(struct _EXCEPTION_POINTERS* exceptionPointers, void* theParam) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + SO_TOLERANT; + MODE_ANY; + } CONTRACTL_END; + + // Backward compatibility: Convert bad image format exceptions thrown while resolving tokens + // to simple true/false successes. This is done for backward compatibility only. Ideally, + // we would always treat bad tokens in the IL stream as fatal errors. + if (exceptionPointers->ExceptionRecord->ExceptionCode == EXCEPTION_COMPLUS) + { + auto* param = reinterpret_cast<TryResolveTokenFilterParam*>(theParam); + if (!isValidTokenForTryResolveToken(param->m_this, param->m_resolvedToken)) + { + param->m_exceptionPointers = *exceptionPointers; + return EEFilterException(exceptionPointers, nullptr); + } + } + + return EXCEPTION_CONTINUE_SEARCH; +} + +bool CEEInfo::tryResolveToken(CORINFO_RESOLVED_TOKEN* resolvedToken) +{ + // No dynamic contract here because SEH is used + STATIC_CONTRACT_SO_TOLERANT; + STATIC_CONTRACT_THROWS; + STATIC_CONTRACT_GC_TRIGGERS; + STATIC_CONTRACT_MODE_PREEMPTIVE; + + TryResolveTokenFilterParam param; + param.m_this = this; + param.m_resolvedToken = resolvedToken; + param.m_success = true; + + PAL_TRY(TryResolveTokenFilterParam*, pParam, ¶m) + { + pParam->m_this->resolveToken(pParam->m_resolvedToken); + } + PAL_EXCEPT_FILTER(TryResolveTokenFilter) + { + if (param.m_exceptionPointers.ExceptionRecord->ExceptionCode == EXCEPTION_COMPLUS) + { + HandleException(¶m.m_exceptionPointers); + } + + param.m_success = false; + } + PAL_ENDTRY + + return param.m_success; +} + +/*********************************************************************/ // We have a few frequently used constants in mscorlib that are defined as // readonly static fields for historic reasons. Check for them here and // allow them to be treated as actual constants by the JIT. @@ -9655,7 +9765,7 @@ ULONG CEEInfo::GetErrorMessage(__inout_ecount(bufferLength) LPWSTR buffer, ULONG // It is fatal to throw an exception while running a SEH filter clause // so our contract is NOTHROW, NOTRIGGER. // -int CEEInfo::FilterException(struct _EXCEPTION_POINTERS *pExceptionPointers) +LONG EEFilterException(struct _EXCEPTION_POINTERS *pExceptionPointers, void *unused) { CONTRACTL { SO_TOLERANT; @@ -9743,6 +9853,12 @@ int CEEInfo::FilterException(struct _EXCEPTION_POINTERS *pExceptionPointers) return result; } +int CEEInfo::FilterException(struct _EXCEPTION_POINTERS *pExceptionPointers) +{ + WRAPPER_NO_CONTRACT; + return EEFilterException(pExceptionPointers, nullptr); +} + // This code is called if FilterException chose to handle the exception. void CEEInfo::HandleException(struct _EXCEPTION_POINTERS *pExceptionPointers) { diff --git a/src/vm/jitinterface.h b/src/vm/jitinterface.h index 6780fe0911..e31a07d17b 100644 --- a/src/vm/jitinterface.h +++ b/src/vm/jitinterface.h @@ -642,6 +642,10 @@ public: // Resolve metadata token into runtime method handles. void resolveToken(/* IN, OUT */ CORINFO_RESOLVED_TOKEN * pResolvedToken); + // Attempt to resolve a metadata token into a runtime method handle. Returns true + // if resolution succeeded and false otherwise. + bool tryResolveToken(/* IN, OUT */ CORINFO_RESOLVED_TOKEN * pResolvedToken); + void getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_ACCESS_FLAGS flags, diff --git a/src/zap/zapinfo.cpp b/src/zap/zapinfo.cpp index 345a920902..4d2d7f8636 100644 --- a/src/zap/zapinfo.cpp +++ b/src/zap/zapinfo.cpp @@ -3455,6 +3455,12 @@ void ZapInfo::resolveToken(CORINFO_RESOLVED_TOKEN * pResolvedToken) } //----------------------------------------------------------------------------- +bool ZapInfo::tryResolveToken(CORINFO_RESOLVED_TOKEN * pResolvedToken) +{ + return m_pEEJitInfo->tryResolveToken(pResolvedToken); +} + +//----------------------------------------------------------------------------- void ZapInfo::findSig(CORINFO_MODULE_HANDLE tokenScope, unsigned sigTOK, CORINFO_CONTEXT_HANDLE tokenContext, diff --git a/src/zap/zapinfo.h b/src/zap/zapinfo.h index 5fe3dcb76e..7fc93820d2 100644 --- a/src/zap/zapinfo.h +++ b/src/zap/zapinfo.h @@ -587,6 +587,7 @@ public: // ICorModuleInfo void resolveToken(CORINFO_RESOLVED_TOKEN * pResolvedToken); + bool tryResolveToken(CORINFO_RESOLVED_TOKEN * pResolvedToken); void findSig(CORINFO_MODULE_HANDLE module, unsigned sigTOK, CORINFO_CONTEXT_HANDLE context, |