summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGaurav Khanna <gkhanna@microsoft.com>2016-07-29 10:04:51 -0700
committerGitHub <noreply@github.com>2016-07-29 10:04:51 -0700
commitd92493a8c49c79c5c66f268bf971260d244691e8 (patch)
tree9b48d17b7788a49d9d22bf7d233053d5d25004fa
parente3164ceb6fc6f39ff9bbaf93c41008709625df37 (diff)
parent2d2e7661556b4c9f4c7197ead2224bd58a89d251 (diff)
downloadcoreclr-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.h2
-rw-r--r--src/mscorlib/src/System/Runtime/Loader/AssemblyLoadContext.cs29
-rw-r--r--src/vm/assembly.cpp49
-rw-r--r--src/vm/assemblynative.cpp28
-rw-r--r--src/vm/assemblyspec.cpp52
-rw-r--r--src/vm/assemblyspec.hpp37
-rw-r--r--src/vm/pefile.cpp3
-rw-r--r--src/vm/pefile.h26
-rw-r--r--src/vm/typeparse.cpp10
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);