e6f957aabe4067f2b0ed65ec332f89f8a9072745
[platform/upstream/coreclr.git] / src / binder / clrprivbinderassemblyloadcontext.cpp
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.
4
5 #include "common.h"
6 #include "assemblybinder.hpp"
7 #include "clrprivbindercoreclr.h"
8 #include "clrprivbinderassemblyloadcontext.h"
9 #include "clrprivbinderutil.h"
10
11 #if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
12
13 using namespace BINDER_SPACE;
14
15 // ============================================================================
16 // CLRPrivBinderAssemblyLoadContext implementation
17 // ============================================================================
18 HRESULT CLRPrivBinderAssemblyLoadContext::BindAssemblyByNameWorker(BINDER_SPACE::AssemblyName *pAssemblyName,
19                                                        BINDER_SPACE::Assembly **ppCoreCLRFoundAssembly)
20 {
21     VALIDATE_ARG_RET(pAssemblyName != nullptr && ppCoreCLRFoundAssembly != nullptr);
22     HRESULT hr = S_OK;
23     
24 #ifdef _DEBUG
25     // MSCORLIB should be bound using BindToSystem
26     _ASSERTE(!pAssemblyName->IsMscorlib());
27 #endif
28
29     // Do we have the assembly already loaded in the context of the current binder?
30     hr = AssemblyBinder::BindAssembly(&m_appContext,
31                                       pAssemblyName,
32                                       NULL,
33                                       NULL,
34                                       FALSE, //fNgenExplicitBind,
35                                       FALSE, //fExplicitBindToNativeImage,
36                                       false, //excludeAppPaths,
37                                       ppCoreCLRFoundAssembly);
38     if (!FAILED(hr))
39     {
40         _ASSERTE(*ppCoreCLRFoundAssembly != NULL);
41         (*ppCoreCLRFoundAssembly)->SetBinder(this);
42     }
43
44     return hr;
45 }
46
47 HRESULT CLRPrivBinderAssemblyLoadContext::BindAssemblyByName(IAssemblyName     *pIAssemblyName,
48                                                  ICLRPrivAssembly **ppAssembly)
49 {
50     HRESULT hr = S_OK;
51     VALIDATE_ARG_RET(pIAssemblyName != nullptr && ppAssembly != nullptr);
52
53     // DevDiv #933506: Exceptions thrown during AssemblyLoadContext.Load should propagate
54     // EX_TRY
55     {
56         _ASSERTE(m_pTPABinder != NULL);
57         
58         ReleaseHolder<BINDER_SPACE::Assembly> pCoreCLRFoundAssembly;
59         ReleaseHolder<AssemblyName> pAssemblyName;
60
61         SAFE_NEW(pAssemblyName, AssemblyName);
62         IF_FAIL_GO(pAssemblyName->Init(pIAssemblyName));
63         
64         // When LoadContext needs to resolve an assembly reference, it will go through the following lookup order:
65         //
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.
71         //
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.
74         
75         {
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))
80             {
81                 // If we are here, one of the following is possible:
82                 //
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).
86                 //
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.
90                 //
91                 hr = AssemblyBinder::BindUsingHostAssemblyResolver(GetManagedAssemblyLoadContext(), pAssemblyName, pIAssemblyName, m_pTPABinder, &pCoreCLRFoundAssembly);
92                 if (SUCCEEDED(hr))
93                 {
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)
98                     {
99                         pCoreCLRFoundAssembly->SetBinder(this);
100                     }
101                 }
102             }
103         }
104         
105         IF_FAIL_GO(hr);
106         
107         // Extract the assembly reference. 
108         //
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();
113 Exit:;        
114     }
115     // EX_CATCH_HRESULT(hr);
116
117     return hr;
118 }
119
120 HRESULT CLRPrivBinderAssemblyLoadContext::BindUsingPEImage( /* in */ PEImage *pPEImage, 
121                                                             /* in */ BOOL fIsNativeImage, 
122                                                             /* [retval][out] */ ICLRPrivAssembly **ppAssembly)
123 {
124     HRESULT hr = S_OK;
125
126     EX_TRY
127     {
128         ReleaseHolder<BINDER_SPACE::Assembly> pCoreCLRFoundAssembly;
129         ReleaseHolder<BINDER_SPACE::AssemblyName> pAssemblyName;        
130         ReleaseHolder<IMDInternalImport> pIMetaDataAssemblyImport;
131         
132         PEKIND PeKind = peNone;
133         
134         // Get the Metadata interface
135         DWORD dwPAFlags[2];
136         IF_FAIL_GO(BinderAcquireImport(pPEImage, &pIMetaDataAssemblyImport, dwPAFlags, fIsNativeImage));
137         IF_FAIL_GO(AssemblyBinder::TranslatePEToArchitectureType(dwPAFlags, &PeKind));
138         
139         _ASSERTE(pIMetaDataAssemblyImport != NULL);
140         
141         // Using the information we just got, initialize the assemblyname
142         SAFE_NEW(pAssemblyName, AssemblyName);
143         IF_FAIL_GO(pAssemblyName->Init(pIMetaDataAssemblyImport, PeKind));
144         
145         // Validate architecture
146         if (!BINDER_SPACE::Assembly::IsValidArchitecture(pAssemblyName->GetArchitecture()))
147         {
148             IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
149         }
150         
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())
154         {
155             IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
156         }
157
158         hr = AssemblyBinder::BindUsingPEImage(&m_appContext, pAssemblyName, pPEImage, PeKind, pIMetaDataAssemblyImport, &pCoreCLRFoundAssembly);
159         if (hr == S_OK)
160         {
161             _ASSERTE(pCoreCLRFoundAssembly != NULL);
162             pCoreCLRFoundAssembly->SetBinder(this);
163             *ppAssembly = pCoreCLRFoundAssembly.Extract();
164         }
165 Exit:;        
166     }
167     EX_CATCH_HRESULT(hr);
168
169     return hr;
170 }
171                               
172 HRESULT CLRPrivBinderAssemblyLoadContext::VerifyBind(IAssemblyName        *AssemblyName,
173                                          ICLRPrivAssembly     *pAssembly,
174                                          ICLRPrivAssemblyInfo *pAssemblyInfo)
175 {
176     return E_FAIL;
177 }
178          
179 HRESULT CLRPrivBinderAssemblyLoadContext::GetBinderFlags(DWORD *pBinderFlags)
180 {
181     if (pBinderFlags == NULL)
182         return E_INVALIDARG;
183     *pBinderFlags = BINDER_NONE;
184     return S_OK;
185 }
186          
187 HRESULT CLRPrivBinderAssemblyLoadContext::GetBinderID( 
188         UINT_PTR *pBinderId)
189 {
190     *pBinderId = reinterpret_cast<UINT_PTR>(this); 
191     return S_OK;
192 }
193          
194 HRESULT CLRPrivBinderAssemblyLoadContext::FindAssemblyBySpec( 
195             LPVOID pvAppDomain,
196             LPVOID pvAssemblySpec,
197             HRESULT *pResult,
198             ICLRPrivAssembly **ppAssembly)
199 {
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
203     return E_FAIL;
204 }
205
206 //=============================================================================
207 // Creates an instance of the AssemblyLoadContext Binder
208 //
209 // This method does not take a lock since it is invoked from the ctor of the
210 // managed AssemblyLoadContext type.
211 //=============================================================================
212 /* static */
213 HRESULT CLRPrivBinderAssemblyLoadContext::SetupContext(DWORD      dwAppDomainId,
214                                             CLRPrivBinderCoreCLR *pTPABinder,
215                                             UINT_PTR ptrAssemblyLoadContext,                                            
216                                             CLRPrivBinderAssemblyLoadContext **ppBindContext)
217 {
218     HRESULT hr = E_FAIL;
219     EX_TRY
220     {
221         if(ppBindContext != NULL)
222         {
223             ReleaseHolder<CLRPrivBinderAssemblyLoadContext> pBinder;
224             
225             SAFE_NEW(pBinder, CLRPrivBinderAssemblyLoadContext);
226             hr = pBinder->m_appContext.Init();
227             if(SUCCEEDED(hr))
228             {
229                 // Save the reference to the AppDomain in which the binder lives
230                 pBinder->m_appContext.SetAppDomainId(dwAppDomainId);
231                 
232                 // Mark that this binder can explicitly bind to native images
233                 pBinder->m_appContext.SetExplicitBindToNativeImages(true);
234                 
235                 // Save reference to the TPABinder that is required to be present.
236                 _ASSERTE(pTPABinder != NULL);
237                 pBinder->m_pTPABinder = pTPABinder;
238                 
239                 // Save the reference to the IntPtr for GCHandle for the managed
240                 // AssemblyLoadContext instance
241                 pBinder->m_ptrManagedAssemblyLoadContext = ptrAssemblyLoadContext;
242
243                 // Return reference to the allocated Binder instance
244                 *ppBindContext = clr::SafeAddRef(pBinder.Extract());
245             }
246         }
247     }
248     EX_CATCH_HRESULT(hr);
249
250 Exit:
251     return hr;
252 }
253
254 CLRPrivBinderAssemblyLoadContext::CLRPrivBinderAssemblyLoadContext()
255 {
256     m_pTPABinder = NULL;
257 }
258
259 #endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)