diff options
author | Gaurav Khanna <gkhanna@microsoft.com> | 2016-07-29 10:04:51 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-07-29 10:04:51 -0700 |
commit | d92493a8c49c79c5c66f268bf971260d244691e8 (patch) | |
tree | 9b48d17b7788a49d9d22bf7d233053d5d25004fa | |
parent | e3164ceb6fc6f39ff9bbaf93c41008709625df37 (diff) | |
parent | 2d2e7661556b4c9f4c7197ead2224bd58a89d251 (diff) | |
download | coreclr-d92493a8c49c79c5c66f268bf971260d244691e8.tar.gz coreclr-d92493a8c49c79c5c66f268bf971260d244691e8.tar.bz2 coreclr-d92493a8c49c79c5c66f268bf971260d244691e8.zip |
Merge pull request #6506 from gkhanna79/FixReflectionLoadContext
Enable RefEmitted assemblies to have Fallback LoadContext notion
-rw-r--r-- | src/dlls/mscorrc/resource.h | 2 | ||||
-rw-r--r-- | src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs | 29 | ||||
-rw-r--r-- | src/vm/assembly.cpp | 49 | ||||
-rw-r--r-- | src/vm/assemblynative.cpp | 28 | ||||
-rw-r--r-- | src/vm/assemblyspec.cpp | 52 | ||||
-rw-r--r-- | src/vm/assemblyspec.hpp | 37 | ||||
-rw-r--r-- | src/vm/pefile.cpp | 3 | ||||
-rw-r--r-- | src/vm/pefile.h | 26 | ||||
-rw-r--r-- | src/vm/typeparse.cpp | 10 |
9 files changed, 200 insertions, 36 deletions
diff --git a/src/dlls/mscorrc/resource.h b/src/dlls/mscorrc/resource.h index 759cb54b30..1391a21545 100644 --- a/src/dlls/mscorrc/resource.h +++ b/src/dlls/mscorrc/resource.h @@ -946,3 +946,5 @@ #endif // FEATURE_HOST_ASSEMBLY_RESOLVER #define IDS_NATIVE_IMAGE_CANNOT_BE_LOADED_MULTIPLE_TIMES 0x263a + + diff --git a/src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs b/src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs index 527fbe4d6c..c4872e363b 100644 --- a/src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs +++ b/src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs @@ -401,19 +401,26 @@ namespace System.Runtime.Loader } AssemblyLoadContext loadContextForAssembly = null; - IntPtr ptrAssemblyLoadContext = GetLoadContextForAssembly((RuntimeAssembly)assembly); - if (ptrAssemblyLoadContext == IntPtr.Zero) - { - // If the load context is returned null, then the assembly was bound using the TPA binder - // and we shall return reference to the active "Default" binder - which could be the TPA binder - // or an overridden CLRPrivBinderAssemblyLoadContext instance. - loadContextForAssembly = AssemblyLoadContext.Default; - } - else + + RuntimeAssembly rtAsm = assembly as RuntimeAssembly; + + // We only support looking up load context for runtime assemblies. + if (rtAsm != null) { - loadContextForAssembly = (AssemblyLoadContext)(GCHandle.FromIntPtr(ptrAssemblyLoadContext).Target); + IntPtr ptrAssemblyLoadContext = GetLoadContextForAssembly(rtAsm); + if (ptrAssemblyLoadContext == IntPtr.Zero) + { + // If the load context is returned null, then the assembly was bound using the TPA binder + // and we shall return reference to the active "Default" binder - which could be the TPA binder + // or an overridden CLRPrivBinderAssemblyLoadContext instance. + loadContextForAssembly = AssemblyLoadContext.Default; + } + else + { + loadContextForAssembly = (AssemblyLoadContext)(GCHandle.FromIntPtr(ptrAssemblyLoadContext).Target); + } } - + return loadContextForAssembly; } diff --git a/src/vm/assembly.cpp b/src/vm/assembly.cpp index 06effd7240..481bceaf55 100644 --- a/src/vm/assembly.cpp +++ b/src/vm/assembly.cpp @@ -756,6 +756,55 @@ Assembly *Assembly::CreateDynamic(AppDomain *pDomain, CreateDynamicAssemblyArgs name, &assemData, dwFlags, &ma)); pFile = PEAssembly::Create(pCallerAssembly->GetManifestFile(), pAssemblyEmit, args->access & ASSEMBLY_ACCESS_REFLECTION_ONLY); + +#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + // Dynamically created modules (aka RefEmit assemblies) do not have a LoadContext associated with them since they are not bound + // using an actual binder. As a result, we will assume the same binding/loadcontext information for the dynamic assembly as its + // caller/creator to ensure that any assembly loads triggered by the dynamic assembly are resolved using the intended load context. + // + // If the creator assembly has a HostAssembly associated with it, then use it for binding. Otherwise, ithe creator is dynamic + // and will have a fallback load context binder associated with it. + ICLRPrivBinder *pFallbackLoadContextBinder = nullptr; + + // There is always a manifest file - wehther working with static or dynamic assemblies. + PEFile *pCallerAssemblyManifestFile = pCallerAssembly->GetManifestFile(); + _ASSERTE(pCallerAssemblyManifestFile != NULL); + + if (!pCallerAssemblyManifestFile->IsDynamic()) + { + // Static assemblies with do not have fallback load context + _ASSERTE(pCallerAssemblyManifestFile->GetFallbackLoadContextBinder() == nullptr); + + if (pCallerAssemblyManifestFile->IsSystem()) + { + // CoreLibrary is always bound to TPA binder + pFallbackLoadContextBinder = pDomain->GetTPABinderContext(); + } + else + { + // Fetch the binder from the host assembly + PTR_ICLRPrivAssembly pCallerAssemblyHostAssembly = pCallerAssemblyManifestFile->GetHostAssembly(); + _ASSERTE(pCallerAssemblyHostAssembly != nullptr); + + UINT_PTR assemblyBinderID = 0; + IfFailThrow(pCallerAssemblyHostAssembly->GetBinderID(&assemblyBinderID)); + pFallbackLoadContextBinder = reinterpret_cast<ICLRPrivBinder *>(assemblyBinderID); + } + } + else + { + // Creator assembly is dynamic too, so use its fallback load context for the one + // we are creating. + pFallbackLoadContextBinder = pCallerAssemblyManifestFile->GetFallbackLoadContextBinder(); + } + + // At this point, we should have a fallback load context binder to work with + _ASSERTE(pFallbackLoadContextBinder != nullptr); + + // Set it as the fallback load context binder for the dynamic assembly being created + pFile->SetFallbackLoadContextBinder(pFallbackLoadContextBinder); +#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + } AssemblyLoadSecurity loadSecurity; diff --git a/src/vm/assemblynative.cpp b/src/vm/assemblynative.cpp index c8251711ad..29e0a451f0 100644 --- a/src/vm/assemblynative.cpp +++ b/src/vm/assemblynative.cpp @@ -179,6 +179,7 @@ FCIMPL9(Object*, AssemblyNative::Load, AssemblyNameBaseObject* assemblyNameUNSAF CheckPointHolder cph(pThread->m_MarshalAlloc.GetCheckpoint()); //hold checkpoint for autorelease DomainAssembly * pParentAssembly = NULL; + Assembly * pRefAssembly = NULL; if(gc.assemblyName->GetSimpleName() == NULL) { @@ -194,7 +195,6 @@ FCIMPL9(Object*, AssemblyNative::Load, AssemblyNameBaseObject* assemblyNameUNSAF gc.codeBase = NULL; // Compute parent assembly - Assembly * pRefAssembly; if (gc.requestingAssembly == NULL) { pRefAssembly = SystemDomain::GetCallersAssembly(stackMark); @@ -241,7 +241,17 @@ FCIMPL9(Object*, AssemblyNative::Load, AssemblyNameBaseObject* assemblyNameUNSAF if (pParentAssembly != NULL) spec.SetParentAssembly(pParentAssembly); - + +#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + // If the requesting assembly has Fallback LoadContext binder available, + // then set it up in the AssemblySpec. + if (pRefAssembly != NULL) + { + PEFile *pRefAssemblyManifestFile = pRefAssembly->GetManifestFile(); + spec.SetFallbackLoadContextBinderForRequestingAssembly(pRefAssemblyManifestFile->GetFallbackLoadContextBinder()); + } +#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + AssemblyLoadSecurity loadSecurity; loadSecurity.m_pAdditionalEvidence = &gc.security; loadSecurity.m_fCheckLoadFromRemoteSource = !!(gc.codeBase != NULL); @@ -2552,20 +2562,26 @@ INT_PTR QCALLTYPE AssemblyNative::GetLoadContextForAssembly(QCall::AssemblyHandl { // Get the binding context for the assembly. // + ICLRPrivBinder *pOpaqueBinder = nullptr; + AppDomain *pCurDomain = AppDomain::GetCurrentDomain(); + CLRPrivBinderCoreCLR *pTPABinder = pCurDomain->GetTPABinderContext(); + + // GetBindingContext returns a ICLRPrivAssembly which can be used to get access to the // actual ICLRPrivBinder instance in which the assembly was loaded. PTR_ICLRPrivBinder pBindingContext = pPEAssembly->GetBindingContext(); UINT_PTR assemblyBinderID = 0; IfFailThrow(pBindingContext->GetBinderID(&assemblyBinderID)); - AppDomain *pCurDomain = AppDomain::GetCurrentDomain(); - CLRPrivBinderCoreCLR *pTPABinder = pCurDomain->GetTPABinderContext(); - // If the assembly was bound using the TPA binder, // then we will return the reference to "Default" binder from the managed implementation when this QCall returns. // // See earlier comment about "Default" binder for additional context. - ICLRPrivBinder *pOpaqueBinder = reinterpret_cast<ICLRPrivBinder *>(assemblyBinderID); + pOpaqueBinder = reinterpret_cast<ICLRPrivBinder *>(assemblyBinderID); + + // We should have a load context binder at this point. + _ASSERTE(pOpaqueBinder != nullptr); + if (!AreSameBinderInstance(pTPABinder, pOpaqueBinder)) { // Only CLRPrivBinderAssemblyLoadContext instance contains the reference to its diff --git a/src/vm/assemblyspec.cpp b/src/vm/assemblyspec.cpp index 5baf588cb2..3bd6d38861 100644 --- a/src/vm/assemblyspec.cpp +++ b/src/vm/assemblyspec.cpp @@ -1256,26 +1256,40 @@ ICLRPrivBinder* AssemblySpec::GetBindingContextFromParentAssembly(AppDomain *pDo // ICLRPrivAssembly implements ICLRPrivBinder and thus, "is a" binder in a manner of semantics. pParentAssemblyBinder = pParentPEAssembly->GetBindingContext(); - + } + #if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) - if (pParentAssemblyBinder != NULL) + if (pParentAssemblyBinder == NULL) + { + // If the parent assembly binder is not available, then we maybe dealing with one of the following + // assembly scenarios: + // + // 1) Domain Neutral assembly + // 2) RefEmitted assembly + // 3) Entrypoint assembly + // + // For (1) and (3), we will need to bind against the DefaultContext binder (aka TPA Binder). This happens + // below if we do not find the parent assembly binder. + // + // For (2), check if we have the fallback load context binder for the requesting dynamic assembly available. + + pParentAssemblyBinder = GetFallbackLoadContextBinderForRequestingAssembly(); + } + + if (pParentAssemblyBinder != NULL) + { + CLRPrivBinderCoreCLR *pTPABinder = pDomain->GetTPABinderContext(); + if (AreSameBinderInstance(pTPABinder, pParentAssemblyBinder)) { - CLRPrivBinderCoreCLR *pTPABinder = pDomain->GetTPABinderContext(); - if (AreSameBinderInstance(pTPABinder, pParentAssemblyBinder)) - { - // If the parent assembly is a platform (TPA) assembly, then its binding context will always be the TPABinder context. In - // such case, we will return the default context for binding to allow the bind to go - // via the custom binder context, if it was overridden. If it was not overridden, then we will get the expected - // TPABinder context anyways. - // - // Get the reference to the default binding context (this could be the TPABinder context or custom AssemblyLoadContext) - pParentAssemblyBinder = static_cast<ICLRPrivBinder*>(pDomain->GetFusionContext()); - } + // If the parent assembly is a platform (TPA) assembly, then its binding context will always be the TPABinder context. In + // such case, we will return the default context for binding to allow the bind to go + // via the custom binder context, if it was overridden. If it was not overridden, then we will get the expected + // TPABinder context anyways. + // + // Get the reference to the default binding context (this could be the TPABinder context or custom AssemblyLoadContext) + pParentAssemblyBinder = static_cast<ICLRPrivBinder*>(pDomain->GetFusionContext()); } -#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) } - -#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) #if defined(FEATURE_COMINTEROP) if (!IsContentType_WindowsRuntime() && (pParentAssemblyBinder != NULL)) @@ -1295,10 +1309,10 @@ ICLRPrivBinder* AssemblySpec::GetBindingContextFromParentAssembly(AppDomain *pDo if (!pParentAssemblyBinder) { - // We can be here when loading assemblies via the host (e.g. ICLRRuntimeHost2::ExecuteAssembly) or when attempting - // to load assemblies via custom AssemblyLoadContext implementation. + // We can be here when loading assemblies via the host (e.g. ICLRRuntimeHost2::ExecuteAssembly) or dealing with assemblies + // whose parent is a domain neutral assembly (see comment above for details). // - // In such a case, the parent assembly (semantically) is mscorlib and thus, the default binding context should be + // In such a case, the parent assembly (semantically) is CoreLibrary and thus, the default binding context should be // used as the parent assembly binder. pParentAssemblyBinder = static_cast<ICLRPrivBinder*>(pDomain->GetFusionContext()); } diff --git a/src/vm/assemblyspec.hpp b/src/vm/assemblyspec.hpp index 4a7130bd28..84e67dfcc2 100644 --- a/src/vm/assemblyspec.hpp +++ b/src/vm/assemblyspec.hpp @@ -42,6 +42,11 @@ class AssemblySpec : public BaseAssemblySpec DWORD m_dwHashAlg; DomainAssembly *m_pParentAssembly; +#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + // Contains the reference to the fallback load context associated with RefEmitted assembly requesting the load of another assembly (static or dynamic) + ICLRPrivBinder *m_pFallbackLoadContextBinder; +#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + BOOL IsValidAssemblyName(); HRESULT InitializeSpecInternal(mdToken kAssemblyRefOrDef, @@ -67,6 +72,11 @@ class AssemblySpec : public BaseAssemblySpec { LIMITED_METHOD_CONTRACT; m_pParentAssembly = NULL; + +#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + m_pFallbackLoadContextBinder = NULL; +#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + } #endif //!DACCESS_COMPILE @@ -74,6 +84,11 @@ class AssemblySpec : public BaseAssemblySpec { LIMITED_METHOD_CONTRACT m_pParentAssembly = NULL; + +#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + m_pFallbackLoadContextBinder = NULL; +#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + } #ifdef FEATURE_FUSION @@ -158,6 +173,22 @@ class AssemblySpec : public BaseAssemblySpec #endif } +#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + void SetFallbackLoadContextBinderForRequestingAssembly(ICLRPrivBinder *pFallbackLoadContextBinder) + { + LIMITED_METHOD_CONTRACT; + + m_pFallbackLoadContextBinder = pFallbackLoadContextBinder; + } + + ICLRPrivBinder* GetFallbackLoadContextBinderForRequestingAssembly() + { + LIMITED_METHOD_CONTRACT; + + return m_pFallbackLoadContextBinder; + } +#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + // Note that this method does not clone the fields! void CopyFrom(AssemblySpec* pSource) { @@ -173,6 +204,12 @@ class AssemblySpec : public BaseAssemblySpec SetIntrospectionOnly(pSource->IsIntrospectionOnly()); SetParentAssembly(pSource->GetParentAssembly()); + +#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + // Copy the details of the fallback load context binder + SetFallbackLoadContextBinderForRequestingAssembly(pSource->GetFallbackLoadContextBinderForRequestingAssembly()); +#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + m_HashForControl = pSource->m_HashForControl; m_dwHashAlg = pSource->m_dwHashAlg; } diff --git a/src/vm/pefile.cpp b/src/vm/pefile.cpp index 440281e953..86785e2417 100644 --- a/src/vm/pefile.cpp +++ b/src/vm/pefile.cpp @@ -99,6 +99,9 @@ PEFile::PEFile(PEImage *identity, BOOL fCheckAuthenticodeSignature/*=TRUE*/) : ,m_securityManagerLock(CrstPEFileSecurityManager) #endif // FEATURE_CAS_POLICY ,m_pHostAssembly(nullptr) +#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + ,m_pFallbackLoadContextBinder(nullptr) +#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) { CONTRACTL { diff --git a/src/vm/pefile.h b/src/vm/pefile.h index 5cefd5d2bd..413d08c185 100644 --- a/src/vm/pefile.h +++ b/src/vm/pefile.h @@ -659,6 +659,17 @@ public: protected: PTR_ICLRPrivAssembly m_pHostAssembly; +#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + // For certain assemblies, we do not have m_pHostAssembly since they are not bound using an actual binder. + // An example is Ref-Emitted assemblies. Thus, when such assemblies trigger load of their dependencies, + // we need to ensure they are loaded in appropriate load context. + // + // To enable this, we maintain a concept of "Fallback LoadContext", which will be set to the Binder of the + // assembly that created the dynamic assembly. If the creator assembly is dynamic itself, then its fallback + // load context would be propagated to the assembly being dynamically generated. + ICLRPrivBinder *m_pFallbackLoadContextBinder; +#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + protected: friend class CLRPrivBinderFusion; @@ -684,6 +695,21 @@ public: bool CanUseWithBindingCache() { LIMITED_METHOD_CONTRACT; return !HasHostAssembly(); } + +#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + void SetFallbackLoadContextBinder(ICLRPrivBinder *pFallbackLoadContextBinder) + { + LIMITED_METHOD_CONTRACT; + m_pFallbackLoadContextBinder = pFallbackLoadContextBinder; + } + + ICLRPrivBinder *GetFallbackLoadContextBinder() + { + LIMITED_METHOD_CONTRACT; + + return m_pFallbackLoadContextBinder; + } +#endif //defined(FEATURE_HOST_ASSEMBLY_RESOLVER) }; // class PEFile diff --git a/src/vm/typeparse.cpp b/src/vm/typeparse.cpp index 0b601f36ce..356cb78423 100644 --- a/src/vm/typeparse.cpp +++ b/src/vm/typeparse.cpp @@ -1902,6 +1902,16 @@ DomainAssembly * LoadDomainAssembly( spec.SetParentAssembly(pRequestingAssembly->GetDomainAssembly()); } +#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + // If the requesting assembly has Fallback LoadContext binder available, + // then set it up in the AssemblySpec. + if (pRequestingAssembly != NULL) + { + PEFile *pRequestingAssemblyManifestFile = pRequestingAssembly->GetManifestFile(); + spec.SetFallbackLoadContextBinderForRequestingAssembly(pRequestingAssemblyManifestFile->GetFallbackLoadContextBinder()); + } +#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + if (bThrowIfNotFound) { pDomainAssembly = spec.LoadDomainAssembly(FILE_LOADED); |