1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
6 #include "assemblybinder.hpp"
7 #include "clrprivbindercoreclr.h"
8 #include "clrprivbinderassemblyloadcontext.h"
9 #include "clrprivbinderutil.h"
11 #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
13 using namespace BINDER_SPACE;
15 // ============================================================================
16 // CLRPrivBinderAssemblyLoadContext implementation
17 // ============================================================================
18 HRESULT CLRPrivBinderAssemblyLoadContext::BindAssemblyByNameWorker(BINDER_SPACE::AssemblyName *pAssemblyName,
19 BINDER_SPACE::Assembly **ppCoreCLRFoundAssembly)
21 VALIDATE_ARG_RET(pAssemblyName != nullptr && ppCoreCLRFoundAssembly != nullptr);
25 // MSCORLIB should be bound using BindToSystem
26 _ASSERTE(!pAssemblyName->IsMscorlib());
29 // Do we have the assembly already loaded in the context of the current binder?
30 hr = AssemblyBinder::BindAssembly(&m_appContext,
34 FALSE, //fNgenExplicitBind,
35 FALSE, //fExplicitBindToNativeImage,
36 false, //excludeAppPaths,
37 ppCoreCLRFoundAssembly);
40 _ASSERTE(*ppCoreCLRFoundAssembly != NULL);
41 (*ppCoreCLRFoundAssembly)->SetBinder(this);
47 HRESULT CLRPrivBinderAssemblyLoadContext::BindAssemblyByName(IAssemblyName *pIAssemblyName,
48 ICLRPrivAssembly **ppAssembly)
51 VALIDATE_ARG_RET(pIAssemblyName != nullptr && ppAssembly != nullptr);
53 // DevDiv #933506: Exceptions thrown during AssemblyLoadContext.Load should propagate
56 _ASSERTE(m_pTPABinder != NULL);
58 ReleaseHolder<BINDER_SPACE::Assembly> pCoreCLRFoundAssembly;
59 ReleaseHolder<AssemblyName> pAssemblyName;
61 SAFE_NEW(pAssemblyName, AssemblyName);
62 IF_FAIL_GO(pAssemblyName->Init(pIAssemblyName));
64 // When LoadContext needs to resolve an assembly reference, it will go through the following lookup order:
66 // 1) Lookup the assembly within the LoadContext itself. If assembly is found, use it.
67 // 2) Invoke the LoadContext's Load method implementation. If assembly is found, use it.
68 // 3) Lookup the assembly within TPABinder. If assembly is found, use it.
69 // 4) Invoke the LoadContext's Resolving event. If assembly is found, use it.
70 // 5) Raise exception.
72 // This approach enables a LoadContext to override assemblies that have been loaded in TPA context by loading
73 // a different (or even the same!) version.
76 // Step 1 - Try to find the assembly within the LoadContext.
77 hr = BindAssemblyByNameWorker(pAssemblyName, &pCoreCLRFoundAssembly);
78 if ((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) ||
79 (hr == FUSION_E_APP_DOMAIN_LOCKED) || (hr == FUSION_E_REF_DEF_MISMATCH))
81 // If we are here, one of the following is possible:
83 // 1) The assembly has not been found in the current binder's application context (i.e. it has not already been loaded), OR
84 // 2) An assembly with the same simple name was already loaded in the context of the current binder but we ran into a Ref/Def
85 // mismatch (either due to version difference or strong-name difference).
87 // Thus, if default binder has been overridden, then invoke it in an attempt to perform the binding for it make the call
88 // of what to do next. The host-overridden binder can either fail the bind or return reference to an existing assembly
89 // that has been loaded.
91 hr = AssemblyBinder::BindUsingHostAssemblyResolver(GetManagedAssemblyLoadContext(), pAssemblyName, pIAssemblyName, m_pTPABinder, &pCoreCLRFoundAssembly);
94 // We maybe returned an assembly that was bound to a different AssemblyLoadContext instance.
95 // In such a case, we will not overwrite the binding context (which would be wrong since it would not
96 // be present in the cache of the current binding context).
97 if (pCoreCLRFoundAssembly->GetBinder() == NULL)
99 pCoreCLRFoundAssembly->SetBinder(this);
107 // Extract the assembly reference.
109 // For TPA assemblies that were bound, TPABinder
110 // would have already set the binder reference for the assembly, so we just need to
111 // extract the reference now.
112 *ppAssembly = pCoreCLRFoundAssembly.Extract();
115 // EX_CATCH_HRESULT(hr);
120 HRESULT CLRPrivBinderAssemblyLoadContext::BindUsingPEImage( /* in */ PEImage *pPEImage,
121 /* in */ BOOL fIsNativeImage,
122 /* [retval][out] */ ICLRPrivAssembly **ppAssembly)
128 ReleaseHolder<BINDER_SPACE::Assembly> pCoreCLRFoundAssembly;
129 ReleaseHolder<BINDER_SPACE::AssemblyName> pAssemblyName;
130 ReleaseHolder<IMDInternalImport> pIMetaDataAssemblyImport;
132 PEKIND PeKind = peNone;
134 // Get the Metadata interface
136 IF_FAIL_GO(BinderAcquireImport(pPEImage, &pIMetaDataAssemblyImport, dwPAFlags, fIsNativeImage));
137 IF_FAIL_GO(AssemblyBinder::TranslatePEToArchitectureType(dwPAFlags, &PeKind));
139 _ASSERTE(pIMetaDataAssemblyImport != NULL);
141 // Using the information we just got, initialize the assemblyname
142 SAFE_NEW(pAssemblyName, AssemblyName);
143 IF_FAIL_GO(pAssemblyName->Init(pIMetaDataAssemblyImport, PeKind));
145 // Validate architecture
146 if (!BINDER_SPACE::Assembly::IsValidArchitecture(pAssemblyName->GetArchitecture()))
148 IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
151 // Disallow attempt to bind to the core library. Aside from that,
152 // the LoadContext can load any assembly (even if it was in a different LoadContext like TPA).
153 if (pAssemblyName->IsMscorlib())
155 IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
158 hr = AssemblyBinder::BindUsingPEImage(&m_appContext, pAssemblyName, pPEImage, PeKind, pIMetaDataAssemblyImport, &pCoreCLRFoundAssembly);
161 _ASSERTE(pCoreCLRFoundAssembly != NULL);
162 pCoreCLRFoundAssembly->SetBinder(this);
163 *ppAssembly = pCoreCLRFoundAssembly.Extract();
167 EX_CATCH_HRESULT(hr);
172 HRESULT CLRPrivBinderAssemblyLoadContext::VerifyBind(IAssemblyName *AssemblyName,
173 ICLRPrivAssembly *pAssembly,
174 ICLRPrivAssemblyInfo *pAssemblyInfo)
179 HRESULT CLRPrivBinderAssemblyLoadContext::GetBinderFlags(DWORD *pBinderFlags)
181 if (pBinderFlags == NULL)
183 *pBinderFlags = BINDER_NONE;
187 HRESULT CLRPrivBinderAssemblyLoadContext::GetBinderID(
190 *pBinderId = reinterpret_cast<UINT_PTR>(this);
194 HRESULT CLRPrivBinderAssemblyLoadContext::FindAssemblyBySpec(
196 LPVOID pvAssemblySpec,
198 ICLRPrivAssembly **ppAssembly)
200 // We are not using a cache at this level
201 // However, assemblies bound by the CoreCLR binder is already cached in the
202 // AppDomain and will be resolved from there if required
206 //=============================================================================
207 // Creates an instance of the AssemblyLoadContext Binder
209 // This method does not take a lock since it is invoked from the ctor of the
210 // managed AssemblyLoadContext type.
211 //=============================================================================
213 HRESULT CLRPrivBinderAssemblyLoadContext::SetupContext(DWORD dwAppDomainId,
214 CLRPrivBinderCoreCLR *pTPABinder,
215 UINT_PTR ptrAssemblyLoadContext,
216 CLRPrivBinderAssemblyLoadContext **ppBindContext)
221 if(ppBindContext != NULL)
223 ReleaseHolder<CLRPrivBinderAssemblyLoadContext> pBinder;
225 SAFE_NEW(pBinder, CLRPrivBinderAssemblyLoadContext);
226 hr = pBinder->m_appContext.Init();
229 // Save the reference to the AppDomain in which the binder lives
230 pBinder->m_appContext.SetAppDomainId(dwAppDomainId);
232 // Mark that this binder can explicitly bind to native images
233 pBinder->m_appContext.SetExplicitBindToNativeImages(true);
235 // Save reference to the TPABinder that is required to be present.
236 _ASSERTE(pTPABinder != NULL);
237 pBinder->m_pTPABinder = pTPABinder;
239 // Save the reference to the IntPtr for GCHandle for the managed
240 // AssemblyLoadContext instance
241 pBinder->m_ptrManagedAssemblyLoadContext = ptrAssemblyLoadContext;
243 // Return reference to the allocated Binder instance
244 *ppBindContext = clr::SafeAddRef(pBinder.Extract());
248 EX_CATCH_HRESULT(hr);
254 CLRPrivBinderAssemblyLoadContext::CLRPrivBinderAssemblyLoadContext()
259 #endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)