From e3f58a3d91f49c6d50aee2068aa885fe74428713 Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Sat, 9 Feb 2019 16:07:14 +0100 Subject: [PATCH] Add reporting exception from ResolveEHClause (#17947) * Add reporting exception from ResolveEHClause When an exception, like EEFileLoadException happens in the ResolveEHClause, it was not caught by the runtime and so it caused exit with `terminating with uncaught exception of type EEFileLoadException*` message without any additional details. This change adds catching the exception, reporting its details and call stack and then failing fast. * Change StackSString to SString * Ensure the catch clause types are loaded before EH In crossgen-ed images, ensure the types used in catch clauses are loaded before the function containing these clauses is executed. That ensures that a failure to load the EH clause type will occur at that time instead of during the EH stack walking that searches for the catch handler. * Fix EH clause class module check * Remove the EH clause class module check It turns out that even if the class was from the current module, it may depend on types from other modules, so we still need to add a fixup for it. --- src/vm/exceptionhandling.cpp | 14 +++++++++++++- src/zap/zapinfo.cpp | 43 ++++++++++++++++++++++++++----------------- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/vm/exceptionhandling.cpp b/src/vm/exceptionhandling.cpp index b97717c..132760b 100644 --- a/src/vm/exceptionhandling.cpp +++ b/src/vm/exceptionhandling.cpp @@ -3041,7 +3041,19 @@ CLRUnwindStatus ExceptionTracker::ProcessManagedCallFrame( } else { - TypeHandle typeHnd = pJitMan->ResolveEHClause(&EHClause, pcfThisFrame); + TypeHandle typeHnd; + EX_TRY + { + typeHnd = pJitMan->ResolveEHClause(&EHClause, pcfThisFrame); + } + EX_CATCH_EX(Exception) + { + SString msg; + GET_EXCEPTION()->GetMessage(msg); + msg.Insert(msg.Begin(), W("Cannot resolve EH clause:\n")); + EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_FAILFAST, msg.GetUnicode()); + } + EX_END_CATCH(RethrowTransientExceptions); EH_LOG((LL_INFO100, " clause type = %s\n", diff --git a/src/zap/zapinfo.cpp b/src/zap/zapinfo.cpp index 9845cae..a56004a 100644 --- a/src/zap/zapinfo.cpp +++ b/src/zap/zapinfo.cpp @@ -1190,20 +1190,8 @@ void ZapInfo::setEHinfo(unsigned EHnumber, { ilClause->ClassToken = clause->ClassToken; - if (m_zapper->m_pOpt->m_compilerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IL_STUB) && (clause->ClassToken != 0)) + if (ilClause->ClassToken != 0) { - // IL stub tokens are 'private' and do not resolve correctly in their parent module's metadata. - - // Currently, the only place we are using a token here is for a COM-to-CLR exception-to-HRESULT - // mapping catch clause. We want this catch clause to catch all exceptions, so we override the - // token to be mdTypeRefNil, which used by the EH system to mean catch(...) - -#ifdef _DEBUG - // The proper way to do this, should we ever want to support arbitrary types here, is to "pre- - // resolve" the token and store the TypeHandle in the clause. But this requires additional - // infrastructure to ensure the TypeHandle is saved and fixed-up properly. For now, we will - // simply assert that the original type was System.Object. - CORINFO_RESOLVED_TOKEN resolvedToken = { 0 }; resolvedToken.tokenContext = MAKE_METHODCONTEXT(m_currentMethodInfo.ftn); resolvedToken.tokenScope = m_currentMethodInfo.scope; @@ -1212,11 +1200,32 @@ void ZapInfo::setEHinfo(unsigned EHnumber, resolveToken(&resolvedToken); - CORINFO_CLASS_HANDLE systemObjectHandle = getBuiltinClass(CLASSID_SYSTEM_OBJECT); - _ASSERTE(systemObjectHandle == resolvedToken.hClass); -#endif // _DEBUG + if (m_zapper->m_pOpt->m_compilerFlags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_IL_STUB)) + { + // IL stub tokens are 'private' and do not resolve correctly in their parent module's metadata. - ilClause->ClassToken = mdTypeRefNil; + // Currently, the only place we are using a token here is for a COM-to-CLR exception-to-HRESULT + // mapping catch clause. We want this catch clause to catch all exceptions, so we override the + // token to be mdTypeRefNil, which used by the EH system to mean catch(...) +#ifdef _DEBUG + // The proper way to do this, should we ever want to support arbitrary types here, is to "pre- + // resolve" the token and store the TypeHandle in the clause. But this requires additional + // infrastructure to ensure the TypeHandle is saved and fixed-up properly. For now, we will + // simply assert that the original type was System.Object. + + CORINFO_CLASS_HANDLE systemObjectHandle = getBuiltinClass(CLASSID_SYSTEM_OBJECT); + _ASSERTE(systemObjectHandle == resolvedToken.hClass); +#endif // _DEBUG + ilClause->ClassToken = mdTypeRefNil; + } + else + { + // For all clause types add fixup to ensure the types are loaded before the code of the method + // containing the catch blocks is executed. This ensures that a failure to load the types would + // not happen when the exception handling is in progress and it is looking for a catch handler. + // At that point, we could only fail fast. + classMustBeLoadedBeforeCodeIsRun(resolvedToken.hClass); + } } } -- 2.7.4