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//
6// AssemblyBinder.cpp
7//
8
9
10//
11// Implements the AssemblyBinder class
12//
13// ============================================================
14
15#include "assemblybinder.hpp"
16#include "assemblyname.hpp"
17
18#include "assembly.hpp"
19#include "applicationcontext.hpp"
20#include "loadcontext.hpp"
21#include "bindresult.inl"
22#include "failurecache.hpp"
23#ifdef FEATURE_VERSIONING_LOG
24#include "bindinglog.hpp"
25#endif // FEATURE_VERSIONING_LOG
26#include "utils.hpp"
27#include "variables.hpp"
28#include "stringarraylist.h"
29
30#include "strongname.h"
31#ifdef FEATURE_VERSIONING_LOG
32#include "../dlls/mscorrc/fusres.h"
33#endif // FEATURE_VERSIONING_LOG
34
35#define APP_DOMAIN_LOCKED_INSPECTION_ONLY 0x01
36#define APP_DOMAIN_LOCKED_UNLOCKED 0x02
37#define APP_DOMAIN_LOCKED_CONTEXT 0x04
38
39#define BIND_BEHAVIOR_STATIC 0
40#define BIND_BEHAVIOR_ORDER_INDEPENDENT 1
41#define BIND_BEHAVIOR_BEST_MATCH 2
42
43#ifndef IMAGE_FILE_MACHINE_ARM64
44#define IMAGE_FILE_MACHINE_ARM64 0xAA64 // ARM64 Little-Endian
45#endif
46
47BOOL IsCompilationProcess();
48
49#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
50#include "clrprivbindercoreclr.h"
51#include "clrprivbinderassemblyloadcontext.h"
52// Helper function in the VM, invoked by the Binder, to invoke the host assembly resolver
53extern HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToBindWithin,
54 IAssemblyName *pIAssemblyName, CLRPrivBinderCoreCLR *pTPABinder,
55 BINDER_SPACE::AssemblyName *pAssemblyName, ICLRPrivAssembly **ppLoadedAssembly);
56
57#endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
58
59namespace BINDER_SPACE
60{
61 namespace
62 {
63 BOOL fAssemblyBinderInitialized = FALSE;
64
65 //
66 // This defines the assembly equivalence relation
67 //
68 HRESULT IsValidAssemblyVersion(/* in */ AssemblyName *pRequestedName,
69 /* in */ AssemblyName *pFoundName,
70 /* in */ ApplicationContext *pApplicationContext)
71 {
72 HRESULT hr = S_OK;
73 BINDER_LOG_ENTER(W("IsValidAssemblyVersion"));
74 AssemblyVersion *pRequestedVersion = pRequestedName->GetVersion();
75 AssemblyVersion *pFoundVersion = pFoundName->GetVersion();
76
77 do
78 {
79 if (!pRequestedVersion->HasMajor())
80 {
81 // An unspecified requested version component matches any value for the same component in the found version,
82 // regardless of lesser-order version components
83 break;
84 }
85 if (!pFoundVersion->HasMajor() || pRequestedVersion->GetMajor() > pFoundVersion->GetMajor())
86 {
87 // - A specific requested version component does not match an unspecified value for the same component in
88 // the found version, regardless of lesser-order version components
89 // - Or, the requested version is greater than the found version
90 hr = FUSION_E_APP_DOMAIN_LOCKED;
91 break;
92 }
93 if (pRequestedVersion->GetMajor() < pFoundVersion->GetMajor())
94 {
95 // The requested version is less than the found version
96 break;
97 }
98
99 if (!pRequestedVersion->HasMinor())
100 {
101 break;
102 }
103 if (!pFoundVersion->HasMinor() || pRequestedVersion->GetMinor() > pFoundVersion->GetMinor())
104 {
105 hr = FUSION_E_APP_DOMAIN_LOCKED;
106 break;
107 }
108 if (pRequestedVersion->GetMinor() < pFoundVersion->GetMinor())
109 {
110 break;
111 }
112
113 if (!pRequestedVersion->HasBuild())
114 {
115 break;
116 }
117 if (!pFoundVersion->HasBuild() || pRequestedVersion->GetBuild() > pFoundVersion->GetBuild())
118 {
119 hr = FUSION_E_APP_DOMAIN_LOCKED;
120 break;
121 }
122 if (pRequestedVersion->GetBuild() < pFoundVersion->GetBuild())
123 {
124 break;
125 }
126
127 if (!pRequestedVersion->HasRevision())
128 {
129 break;
130 }
131 if (!pFoundVersion->HasRevision() || pRequestedVersion->GetRevision() > pFoundVersion->GetRevision())
132 {
133 hr = FUSION_E_APP_DOMAIN_LOCKED;
134 break;
135 }
136 } while (false);
137
138 if (pApplicationContext->IsTpaListProvided() && hr == FUSION_E_APP_DOMAIN_LOCKED)
139 {
140 // For our new binding models, use a more descriptive error code than APP_DOMAIN_LOCKED for bind
141 // failures.
142 hr = FUSION_E_REF_DEF_MISMATCH;
143 }
144
145 BINDER_LOG_LEAVE_HR(W("IsValidAssemblyVersion"), hr)
146 return hr;
147 }
148
149 HRESULT URLToFullPath(PathString &assemblyPath)
150 {
151 HRESULT hr = S_OK;
152
153 SString::Iterator pos = assemblyPath.Begin();
154 if (assemblyPath.MatchCaseInsensitive(pos, g_BinderVariables->httpURLPrefix))
155 {
156 // HTTP downloads are unsupported
157 hr = FUSION_E_CODE_DOWNLOAD_DISABLED;
158 }
159 else
160 {
161 SString fullAssemblyPath;
162 WCHAR *pwzFullAssemblyPath = fullAssemblyPath.OpenUnicodeBuffer(MAX_LONGPATH);
163 DWORD dwCCFullAssemblyPath = MAX_LONGPATH + 1; // SString allocates extra byte for null.
164
165 MutateUrlToPath(assemblyPath);
166
167 dwCCFullAssemblyPath = WszGetFullPathName(assemblyPath.GetUnicode(),
168 dwCCFullAssemblyPath,
169 pwzFullAssemblyPath,
170 NULL);
171 if (dwCCFullAssemblyPath > MAX_LONGPATH)
172 {
173 fullAssemblyPath.CloseBuffer();
174 pwzFullAssemblyPath = fullAssemblyPath.OpenUnicodeBuffer(dwCCFullAssemblyPath - 1);
175 dwCCFullAssemblyPath = WszGetFullPathName(assemblyPath.GetUnicode(),
176 dwCCFullAssemblyPath,
177 pwzFullAssemblyPath,
178 NULL);
179 }
180 fullAssemblyPath.CloseBuffer(dwCCFullAssemblyPath);
181
182 if (dwCCFullAssemblyPath == 0)
183 {
184 hr = HRESULT_FROM_GetLastError();
185 }
186 else
187 {
188 assemblyPath.Set(fullAssemblyPath);
189 }
190 }
191
192 return hr;
193 }
194
195
196#ifdef FEATURE_VERSIONING_LOG
197 //
198 // This function outputs the current binding result
199 // and flushes the bind log.
200 //
201 HRESULT LogBindResult(ApplicationContext *pApplicationContext,
202 HRESULT hrLog,
203 BindResult *pBindResult)
204 {
205 HRESULT hr = S_OK;
206 BindingLog *pBindingLog = pApplicationContext->GetBindingLog();
207
208 if (!pBindingLog->CanLog())
209 {
210 // For non-logging, return the bind result
211 hr = hrLog;
212 goto Exit;
213 }
214
215 IF_FAIL_GO(pBindingLog->LogHR(hrLog));
216
217 if ((hrLog == S_OK) && pBindResult->HaveResult())
218 {
219 IF_FAIL_GO(pBindingLog->LogResult(pBindResult));
220 }
221
222 IF_FAIL_GO(pBindingLog->Flush());
223
224 // For failure-free logging, return the bind result
225 hr = hrLog;
226
227 Exit:
228 // SilverLight does not propagate binding log; therefore kill the information here.
229 pApplicationContext->ClearBindingLog();
230 return hr;
231 }
232
233 inline UINT GetLockedContextEntry(BOOL fInspectionOnly)
234 {
235 if (fInspectionOnly)
236 return ID_FUSLOG_BINDING_LOCKED_ASSEMBLY_INS_CONTEXT;
237 else
238 return ID_FUSLOG_BINDING_LOCKED_ASSEMBLY_EXE_CONTEXT;
239 }
240
241 inline UINT GetLockedEntry(BOOL fInspectionOnly)
242 {
243 if (fInspectionOnly)
244 return ID_FUSLOG_BINDING_LOCKED_MT_INS_LOCKED_ENTRY;
245 else
246 return ID_FUSLOG_BINDING_LOCKED_MT_EXE_LOCKED_ENTRY;
247 }
248
249 inline UINT GetLocalizedEntry(BOOL fInspectionOnly)
250 {
251 if (fInspectionOnly)
252 return ID_FUSLOG_BINDING_LOCKED_MT_INS_LOCALI_ENTRY;
253 else
254 return ID_FUSLOG_BINDING_LOCKED_MT_EXE_LOCALI_ENTRY;
255 }
256
257 inline UINT GetCBaseEntry(BOOL fInspectionOnly)
258 {
259 if (fInspectionOnly)
260 return ID_FUSLOG_BINDING_LOCKED_MT_INS_CBASE_ENTRY;
261 else
262 return ID_FUSLOG_BINDING_LOCKED_MT_EXE_CBASE_ENTRY;
263 }
264
265 HRESULT LogAppDomainLocked(ApplicationContext *pApplicationContext,
266 DWORD dwLockedReason,
267 AssemblyName *pAssemblyName = NULL)
268 {
269 HRESULT hr = S_OK;
270 BindingLog *pBindingLog = pApplicationContext->GetBindingLog();
271
272 if (pBindingLog->CanLog())
273 {
274 PathString info;
275 PathString format;
276 BOOL fInspectionOnly = FALSE;
277
278 if ((dwLockedReason & APP_DOMAIN_LOCKED_INSPECTION_ONLY) != 0)
279 {
280 dwLockedReason &= ~APP_DOMAIN_LOCKED_INSPECTION_ONLY;
281 fInspectionOnly = TRUE;
282 }
283
284 switch (dwLockedReason)
285 {
286 case APP_DOMAIN_LOCKED_UNLOCKED:
287 {
288 IF_FAIL_GO(info.
289 LoadResourceAndReturnHR(CCompRC::Debugging,
290 ID_FUSLOG_BINDING_LOCKED_UNLOCKED));
291 }
292 break;
293 case APP_DOMAIN_LOCKED_CONTEXT:
294 {
295 PathString displayName;
296
297 _ASSERTE(pAssemblyName != NULL);
298
299 IF_FAIL_GO(format.
300 LoadResourceAndReturnHR(CCompRC::Debugging,
301 GetLockedContextEntry(fInspectionOnly)));
302
303 pAssemblyName->GetDisplayName(displayName,
304 AssemblyName::INCLUDE_VERSION |
305 AssemblyName::INCLUDE_ARCHITECTURE);
306
307 info.Printf(format.GetUnicode(), displayName.GetUnicode());
308 }
309 break;
310 default:
311 _ASSERTE(0);
312 IF_FAIL_GO(E_INVALIDARG);
313 break;
314 }
315
316 IF_FAIL_GO(pBindingLog->Log(info));
317 }
318
319 Exit:
320 return hr;
321 }
322
323 HRESULT LogBindBehavior(ApplicationContext *pApplicationContext,
324 DWORD dwBindBehavior)
325 {
326 HRESULT hr = S_OK;
327 BindingLog *pBindingLog = pApplicationContext->GetBindingLog();
328
329 if (pBindingLog->CanLog())
330 {
331 PathString bindBehavior;
332 UINT uiBindBehavior = 0;
333
334 switch (dwBindBehavior)
335 {
336 case BIND_BEHAVIOR_STATIC:
337 uiBindBehavior = ID_FUSLOG_BINDING_BEHAVIOR_STATIC;
338 break;
339 case BIND_BEHAVIOR_ORDER_INDEPENDENT:
340 uiBindBehavior = ID_FUSLOG_BINDING_BEHAVIOR_ORDER_INDEPENDENT;
341 break;
342 case BIND_BEHAVIOR_BEST_MATCH:
343 uiBindBehavior = ID_FUSLOG_BINDING_BEHAVIOR_BEST_MATCH;
344 break;
345 default:
346 _ASSERTE(0);
347 IF_FAIL_GO(E_INVALIDARG);
348 break;
349 }
350
351 IF_FAIL_GO(bindBehavior.LoadResourceAndReturnHR(CCompRC::Debugging, uiBindBehavior));
352 IF_FAIL_GO(pBindingLog->Log(bindBehavior.GetUnicode()));
353 }
354
355 Exit:
356 return hr;
357 }
358
359 HRESULT LogAssemblyNameWhereRef(ApplicationContext *pApplicationContext,
360 Assembly *pAssembly)
361 {
362 HRESULT hr = S_OK;
363 BindingLog *pBindingLog = pApplicationContext->GetBindingLog();
364
365 if (pBindingLog->CanLog())
366 {
367 PathString info;
368
369 IF_FAIL_GO(info.
370 LoadResourceAndReturnHR(CCompRC::Debugging, ID_FUSLOG_BINDING_LOG_WHERE_REF_NAME));
371 IF_FAIL_GO(pBindingLog->LogAssemblyName(info.GetUnicode(),
372 pAssembly->GetAssemblyName()));
373 }
374
375 Exit:
376 return hr;
377 }
378
379 HRESULT LogConfigurationError(ApplicationContext *pApplicationContext,
380 AssemblyName *pCulturedManifestName,
381 AssemblyName *pLocalPathAssemblyName)
382 {
383 HRESULT hr = S_OK;
384 BindingLog *pBindingLog = pApplicationContext->GetBindingLog();
385
386 if (pBindingLog->CanLog())
387 {
388 PathString tmp;
389 PathString culturedManifestDisplayName;
390 PathString localPathDisplayName;
391 PathString info;
392
393 IF_FAIL_GO(tmp.
394 LoadResourceAndReturnHR(CCompRC::Debugging, ID_FUSLOG_BINDING_LOG_ERRONOUS_MANIFEST_ENTRY));
395
396 pCulturedManifestName->GetDisplayName(culturedManifestDisplayName,
397 AssemblyName::INCLUDE_VERSION |
398 AssemblyName::INCLUDE_ARCHITECTURE);
399 pLocalPathAssemblyName->GetDisplayName(localPathDisplayName,
400 AssemblyName::INCLUDE_VERSION |
401 AssemblyName::INCLUDE_ARCHITECTURE);
402
403 info.Printf(tmp.GetUnicode(),
404 culturedManifestDisplayName.GetUnicode(),
405 localPathDisplayName.GetUnicode());
406 IF_FAIL_GO(pBindingLog->Log(info.GetUnicode()));
407 }
408
409 Exit:
410 return hr;
411 }
412
413 HRESULT LogPathAttempt(ApplicationContext *pApplicationContext,
414 PathString &assemblyPath)
415 {
416 HRESULT hr = S_OK;
417 BindingLog *pBindingLog = pApplicationContext->GetBindingLog();
418
419 if (pBindingLog->CanLog())
420 {
421 PathString tmp;
422 PathString info;
423
424 IF_FAIL_GO(tmp.LoadResourceAndReturnHR(CCompRC::Debugging,
425 ID_FUSLOG_BINDING_LOG_PATH_ATTEMPT));
426 info.Printf(tmp.GetUnicode(), assemblyPath.GetUnicode());
427
428 IF_FAIL_GO(pBindingLog->Log(info));
429 }
430
431 Exit:
432 return hr;
433 }
434#endif // FEATURE_VERSIONING_LOG
435
436#ifndef CROSSGEN_COMPILE
437 HRESULT CreateImageAssembly(IMDInternalImport *pIMetaDataAssemblyImport,
438 PEKIND PeKind,
439 PEImage *pPEImage,
440 PEImage *pNativePEImage,
441 BOOL fInspectionOnly,
442 BindResult *pBindResult)
443 {
444 HRESULT hr = S_OK;
445 ReleaseHolder<Assembly> pAssembly;
446 PathString asesmblyPath;
447
448 SAFE_NEW(pAssembly, Assembly);
449 IF_FAIL_GO(pAssembly->Init(pIMetaDataAssemblyImport,
450 PeKind,
451 pPEImage,
452 pNativePEImage,
453 asesmblyPath,
454 fInspectionOnly,
455 FALSE /* fIsInGAC */));
456
457 pBindResult->SetResult(pAssembly);
458 pBindResult->SetIsFirstRequest(TRUE);
459
460 Exit:
461 return hr;
462 }
463#endif // !CROSSGEN_COMPILE
464 };
465
466 /* static */
467 HRESULT AssemblyBinder::Startup()
468 {
469 HRESULT hr = S_OK;
470
471 if (!BINDER_SPACE::fAssemblyBinderInitialized)
472 {
473 g_BinderVariables = new Variables();
474 IF_FAIL_GO(g_BinderVariables->Init());
475
476 // Setup Debug log
477 BINDER_LOG_STARTUP();
478
479 // We're done
480 BINDER_SPACE::fAssemblyBinderInitialized = TRUE;
481 }
482
483 Exit:
484 return hr;
485 }
486
487
488 HRESULT AssemblyBinder::TranslatePEToArchitectureType(DWORD *pdwPAFlags, PEKIND *PeKind)
489 {
490 HRESULT hr = S_OK;
491 BINDER_LOG_ENTER(W("TranslatePEToArchitectureType"))
492
493 _ASSERTE(pdwPAFlags != NULL);
494 _ASSERTE(PeKind != NULL);
495
496 CorPEKind CLRPeKind = (CorPEKind) pdwPAFlags[0];
497 DWORD dwImageType = pdwPAFlags[1];
498
499 *PeKind = peNone;
500
501 if(CLRPeKind == peNot)
502 {
503 // Not a PE. Shouldn't ever get here.
504 BINDER_LOG(W("Not a PE!"));
505 IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
506 }
507 else
508 {
509 if ((CLRPeKind & peILonly) && !(CLRPeKind & pe32Plus) &&
510 !(CLRPeKind & pe32BitRequired) && dwImageType == IMAGE_FILE_MACHINE_I386)
511 {
512 // Processor-agnostic (MSIL)
513 BINDER_LOG(W("Processor-agnostic (MSIL)"));
514 *PeKind = peMSIL;
515 }
516 else if (CLRPeKind & pe32Plus)
517 {
518 // 64-bit
519 if (CLRPeKind & pe32BitRequired)
520 {
521 // Invalid
522 BINDER_LOG(W("CLRPeKind & pe32BitRequired is true"));
523 IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
524 }
525
526 // Regardless of whether ILONLY is set or not, the architecture
527 // is the machine type.
528 if(dwImageType == IMAGE_FILE_MACHINE_ARM64)
529 *PeKind = peARM64;
530 else if (dwImageType == IMAGE_FILE_MACHINE_AMD64)
531 *PeKind = peAMD64;
532 else
533 {
534 // We don't support other architectures
535 BINDER_LOG(W("Unknown architecture"));
536 IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
537 }
538 }
539 else
540 {
541 // 32-bit, non-agnostic
542 if(dwImageType == IMAGE_FILE_MACHINE_I386)
543 *PeKind = peI386;
544 else if(dwImageType == IMAGE_FILE_MACHINE_ARMNT)
545 *PeKind = peARM;
546 else
547 {
548 // Not supported
549 BINDER_LOG(W("32-bit, non-agnostic"));
550 IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
551 }
552 }
553 }
554
555 Exit:
556 BINDER_LOG_LEAVE_HR(W("TranslatePEToArchitectureType"), hr);
557 return hr;
558 }
559
560 // See code:BINDER_SPACE::AssemblyBinder::GetAssembly for info on fNgenExplicitBind
561 // and fExplicitBindToNativeImage, and see code:CEECompileInfo::LoadAssemblyByPath
562 // for an example of how they're used.
563 HRESULT AssemblyBinder::BindAssembly(/* in */ ApplicationContext *pApplicationContext,
564 /* in */ AssemblyName *pAssemblyName,
565 /* in */ LPCWSTR szCodeBase,
566 /* in */ PEAssembly *pParentAssembly,
567 /* in */ BOOL fNgenExplicitBind,
568 /* in */ BOOL fExplicitBindToNativeImage,
569 /* in */ bool excludeAppPaths,
570 /* out */ Assembly **ppAssembly)
571 {
572 HRESULT hr = S_OK;
573 LONG kContextVersion = 0;
574 BindResult bindResult;
575
576 BINDER_LOG_ENTER(W("AssemblyBinder::BindAssembly"));
577
578#ifndef CROSSGEN_COMPILE
579 Retry:
580 {
581 // Lock the binding application context
582 CRITSEC_Holder contextLock(pApplicationContext->GetCriticalSectionCookie());
583#endif
584
585 if (szCodeBase == NULL)
586 {
587#ifdef FEATURE_VERSIONING_LOG
588 // Log bind
589 IF_FAIL_GO(BindingLog::CreateInContext(pApplicationContext,
590 pAssemblyName,
591 pParentAssembly));
592#endif // FEATURE_VERSIONING_LOG
593
594
595 hr = BindByName(pApplicationContext,
596 pAssemblyName,
597 BIND_CACHE_FAILURES,
598 excludeAppPaths,
599 &bindResult);
600 IF_FAIL_GO(hr);
601 }
602 else
603 {
604 PathString assemblyPath(szCodeBase);
605
606#ifdef FEATURE_VERSIONING_LOG
607 // Log bind
608 IF_FAIL_GO(BindingLog::CreateInContext(pApplicationContext,
609 assemblyPath,
610 pParentAssembly));
611#endif // FEATURE_VERSIONING_LOG
612
613 // Convert URL to full path and block HTTP downloads
614 IF_FAIL_GO(URLToFullPath(assemblyPath));
615 BOOL fDoNgenExplicitBind = fNgenExplicitBind;
616
617 // Only use explicit ngen binding in the new coreclr path-based binding model
618 if(!pApplicationContext->IsTpaListProvided())
619 {
620 fDoNgenExplicitBind = FALSE;
621 }
622
623 IF_FAIL_GO(BindWhereRef(pApplicationContext,
624 assemblyPath,
625 fDoNgenExplicitBind,
626 fExplicitBindToNativeImage,
627 excludeAppPaths,
628 &bindResult));
629 }
630
631 // Remember the post-bind version
632 kContextVersion = pApplicationContext->GetVersion();
633
634 Exit:
635#ifdef FEATURE_VERSIONING_LOG
636 hr = LogBindResult(pApplicationContext, hr, &bindResult);
637#else // FEATURE_VERSIONING_LOG
638 ;
639#endif // FEATURE_VERSIONING_LOG
640
641#ifndef CROSSGEN_COMPILE
642 } // lock(pApplicationContext)
643#endif
644
645 if (bindResult.HaveResult())
646 {
647
648#ifndef CROSSGEN_COMPILE
649 BindResult hostBindResult;
650
651 hr = RegisterAndGetHostChosen(pApplicationContext,
652 kContextVersion,
653 &bindResult,
654 &hostBindResult);
655
656 if (hr == S_FALSE)
657 {
658 // Another bind interfered. We need to retry the entire bind.
659 // This by design loops as long as needed because by construction we eventually
660 // will succeed or fail the bind.
661 bindResult.Reset();
662 goto Retry;
663 }
664 else if (hr == S_OK)
665 {
666 *ppAssembly = hostBindResult.GetAsAssembly(TRUE /* fAddRef */);
667 }
668#else // CROSSGEN_COMPILE
669
670 *ppAssembly = bindResult.GetAsAssembly(TRUE /* fAddRef */);
671
672#endif // CROSSGEN_COMPILE
673 }
674
675 BINDER_LOG_LEAVE_HR(W("AssemblyBinder::BindAssembly"), hr);
676 return hr;
677 }
678
679 /* static */
680 HRESULT AssemblyBinder::BindToSystem(SString &systemDirectory,
681 Assembly **ppSystemAssembly,
682 bool fBindToNativeImage)
683 {
684 _ASSERTE(BINDER_SPACE::fAssemblyBinderInitialized == TRUE);
685
686 HRESULT hr = S_OK;
687 BINDER_LOG_ENTER(W("AssemblyBinder:BindToSystem"));
688
689 _ASSERTE(ppSystemAssembly != NULL);
690
691 StackSString sCoreLibDir(systemDirectory);
692 ReleaseHolder<Assembly> pSystemAssembly;
693
694 if(!sCoreLibDir.EndsWith(DIRECTORY_SEPARATOR_CHAR_W))
695 {
696 sCoreLibDir.Append(DIRECTORY_SEPARATOR_CHAR_W);
697 }
698
699 StackSString sCoreLib;
700
701 // At run-time, System.Private.CoreLib.dll is expected to be the NI image.
702 sCoreLib = sCoreLibDir;
703 sCoreLib.Append(CoreLibName_IL_W);
704 BOOL fExplicitBindToNativeImage = (fBindToNativeImage == true)? TRUE:FALSE;
705#ifdef FEATURE_NI_BIND_FALLBACK
706 // Some non-Windows platforms do not automatically generate the NI image as CoreLib.dll.
707 // If those platforms also do not support automatic fallback from NI to IL, bind as IL.
708 fExplicitBindToNativeImage = FALSE;
709#endif // FEATURE_NI_BIND_FALLBACK
710 IF_FAIL_GO(AssemblyBinder::GetAssembly(sCoreLib,
711 FALSE /* fInspectionOnly */,
712 TRUE /* fIsInGAC */,
713 fExplicitBindToNativeImage,
714 &pSystemAssembly));
715
716 *ppSystemAssembly = pSystemAssembly.Extract();
717
718 Exit:
719 BINDER_LOG_LEAVE_HR(W("AssemblyBinder::BindToSystem"), hr);
720 return hr;
721 }
722
723
724 /* static */
725 HRESULT AssemblyBinder::BindToSystemSatellite(SString &systemDirectory,
726 SString &simpleName,
727 SString &cultureName,
728 Assembly **ppSystemAssembly)
729 {
730 _ASSERTE(BINDER_SPACE::fAssemblyBinderInitialized == TRUE);
731
732 HRESULT hr = S_OK;
733 BINDER_LOG_ENTER(W("AssemblyBinder:BindToSystemSatellite"));
734
735 _ASSERTE(ppSystemAssembly != NULL);
736
737 StackSString sMscorlibSatellite(systemDirectory);
738 ReleaseHolder<Assembly> pSystemAssembly;
739
740 // append culture name
741 if (!cultureName.IsEmpty())
742 {
743 CombinePath(sMscorlibSatellite, cultureName, sMscorlibSatellite);
744 }
745
746 // append satellite assembly's simple name
747 CombinePath(sMscorlibSatellite, simpleName, sMscorlibSatellite);
748
749 // append extension
750 sMscorlibSatellite.Append(W(".dll"));
751
752 IF_FAIL_GO(AssemblyBinder::GetAssembly(sMscorlibSatellite,
753 FALSE /* fInspectionOnly */,
754 TRUE /* fIsInGAC */,
755 FALSE /* fExplicitBindToNativeImage */,
756 &pSystemAssembly));
757
758 *ppSystemAssembly = pSystemAssembly.Extract();
759
760 Exit:
761 BINDER_LOG_LEAVE_HR(W("AssemblyBinder::BindToSystemSatellite"), hr);
762 return hr;
763 }
764
765 /* static */
766 HRESULT AssemblyBinder::GetAssemblyFromImage(PEImage *pPEImage,
767 PEImage *pNativePEImage,
768 Assembly **ppAssembly)
769 {
770 _ASSERTE(BINDER_SPACE::fAssemblyBinderInitialized == TRUE);
771
772 HRESULT hr = S_OK;
773 BINDER_LOG_ENTER(W("AssemblyBinder::GetAssemblyFromImage"));
774
775 _ASSERTE(pPEImage != NULL);
776 _ASSERTE(ppAssembly != NULL);
777
778 ReleaseHolder<Assembly> pAssembly;
779 ReleaseHolder<IMDInternalImport> pIMetaDataAssemblyImport;
780 DWORD dwPAFlags[2];
781 PEKIND PeKind = peNone;
782
783 SAFE_NEW(pAssembly, Assembly);
784 if(pNativePEImage)
785 {
786 IF_FAIL_GO(BinderAcquireImport(pNativePEImage, &pIMetaDataAssemblyImport, dwPAFlags, TRUE));
787 }
788 else
789 {
790 IF_FAIL_GO(BinderAcquireImport(pPEImage, &pIMetaDataAssemblyImport, dwPAFlags, FALSE));
791 }
792 IF_FAIL_GO(TranslatePEToArchitectureType(dwPAFlags, &PeKind));
793 IF_FAIL_GO(pAssembly->Init(pIMetaDataAssemblyImport,
794 PeKind,
795 pPEImage,
796 pNativePEImage,
797 g_BinderVariables->emptyString,
798 FALSE /* fInspectionOnly */,
799 FALSE /* fIsInGAC */));
800
801 // TODO: Is this correct?
802 pAssembly->SetIsByteArray(TRUE);
803
804 *ppAssembly = pAssembly.Extract();
805
806 Exit:
807 BINDER_LOG_LEAVE_HR(W("AssemblyBinder::GetAssemblyFromImage"), hr);
808 return hr;
809 }
810
811#ifndef CROSSGEN_COMPILE
812 /* static */
813 HRESULT AssemblyBinder::PreBindByteArray(ApplicationContext *pApplicationContext,
814 PEImage *pPEImage,
815 BOOL fInspectionOnly)
816 {
817 _ASSERTE(BINDER_SPACE::fAssemblyBinderInitialized == TRUE);
818
819 HRESULT hr = S_OK;
820 BINDER_LOG_ENTER(W("AssemblyBinder::PreBindByteArray"));
821
822 ReleaseHolder<AssemblyName> pAssemblyName;
823 BOOL fNeedHostRegister = FALSE;
824 LONG kContextVersion = 0;
825 ReleaseHolder<IMDInternalImport> pIMetaDataAssemblyImport;
826 DWORD dwPAFlags[2];
827 PEKIND PeKind = peNone;
828 BindResult bindResult;
829
830 // Prepare binding data
831 SAFE_NEW(pAssemblyName, AssemblyName);
832 IF_FAIL_GO(BinderAcquireImport(pPEImage, &pIMetaDataAssemblyImport, dwPAFlags, FALSE));
833 IF_FAIL_GO(TranslatePEToArchitectureType(dwPAFlags, &PeKind));
834 IF_FAIL_GO(pAssemblyName->Init(pIMetaDataAssemblyImport, PeKind));
835 pAssemblyName->SetIsDefinition(TRUE);
836
837 // Validate architecture
838 if (!fInspectionOnly && !Assembly::IsValidArchitecture(pAssemblyName->GetArchitecture()))
839 {
840 IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
841 }
842
843 // Attempt the actual bind (eventually more than once)
844 Retry:
845 {
846 // Lock the application context
847 CRITSEC_Holder contextLock(pApplicationContext->GetCriticalSectionCookie());
848
849 // Attempt uncached bind and register stream if possible
850 if (!fInspectionOnly &&
851 ((hr = BindByName(pApplicationContext,
852 pAssemblyName,
853 BIND_CACHE_FAILURES | BIND_CACHE_RERUN_BIND,
854 false, // excludeAppPaths
855 &bindResult)) == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
856 )
857 {
858 if ((fInspectionOnly && !bindResult.HaveResult()) ||
859 (bindResult.GetRetargetedAssemblyName() == NULL))
860 {
861 IF_FAIL_GO(CreateImageAssembly(pIMetaDataAssemblyImport,
862 PeKind,
863 pPEImage,
864 NULL,
865 fInspectionOnly,
866 &bindResult));
867 if (fInspectionOnly)
868 {
869 // For inspection-only, we do not share the map.
870 IF_FAIL_GO(Register(pApplicationContext, fInspectionOnly, &bindResult));
871 }
872 else
873 {
874 // Remember the post-bind version of the context
875 kContextVersion = pApplicationContext->GetVersion();
876 fNeedHostRegister = TRUE;
877 }
878 }
879 }
880 } // lock(pApplicationContext)
881
882 if (fNeedHostRegister)
883 {
884 BindResult hostBindResult;
885
886 // This has to happen outside the binder lock as it can cause new binds
887 IF_FAIL_GO(RegisterAndGetHostChosen(pApplicationContext,
888 kContextVersion,
889 &bindResult,
890 &hostBindResult));
891
892 if (hr == S_FALSE)
893 {
894 // Another bind interfered. We need to retry entire bind.
895 // This by design loops as long as needed because by construction we eventually
896 // will succeed or fail the bind.
897 bindResult.Reset();
898 goto Retry;
899 }
900 }
901
902 // Ignore bind errors here because we need to attempt by-name load to get log entry.
903 GO_WITH_HRESULT(S_OK);
904
905 Exit:
906 BINDER_LOG_LEAVE_HR(W("AssemblyBinder::PreBindByteArray"), hr);
907 return hr;
908 }
909
910#endif //CROSSGEN_COMPILE
911
912 /* static */
913 HRESULT AssemblyBinder::BindByName(ApplicationContext *pApplicationContext,
914 AssemblyName *pAssemblyName,
915 DWORD dwBindFlags,
916 bool excludeAppPaths,
917 BindResult *pBindResult)
918 {
919 HRESULT hr = S_OK;
920 BINDER_LOG_ENTER(W("AssemblyBinder::BindByName"));
921 PathString assemblyDisplayName;
922
923 // Look for already cached binding failure (ignore PA, every PA will lock the context)
924 pAssemblyName->GetDisplayName(assemblyDisplayName,
925 AssemblyName::INCLUDE_VERSION);
926
927 hr = pApplicationContext->GetFailureCache()->Lookup(assemblyDisplayName);
928 if (FAILED(hr))
929 {
930 if ((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) && RerunBind(dwBindFlags))
931 {
932 // Ignore pre-existing transient bind error (re-bind will succeed)
933 pApplicationContext->GetFailureCache()->Remove(assemblyDisplayName);
934 }
935
936 goto LogExit;
937 }
938 else if (hr == S_FALSE)
939 {
940 // workaround: Special case for byte arrays. Rerun the bind to create binding log.
941 pAssemblyName->SetIsDefinition(TRUE);
942 hr = S_OK;
943 }
944
945 if (!Assembly::IsValidArchitecture(pAssemblyName->GetArchitecture()))
946 {
947 // Assembly reference contains wrong architecture
948 IF_FAIL_GO(FUSION_E_INVALID_NAME);
949 }
950
951 IF_FAIL_GO(BindLocked(pApplicationContext,
952 pAssemblyName,
953 dwBindFlags,
954 excludeAppPaths,
955 pBindResult));
956
957 if (!pBindResult->HaveResult())
958 {
959 // Behavior rules are clueless now
960 IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
961 }
962
963 Exit:
964 if (FAILED(hr) && CacheBindFailures(dwBindFlags))
965 {
966 if (RerunBind(dwBindFlags))
967 {
968 if (hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
969 {
970 // Cache non-transient bind error for byte-array
971 hr = S_FALSE;
972 }
973 else
974 {
975 // Ignore transient bind error (re-bind will succeed)
976 goto LogExit;
977 }
978 }
979 hr = pApplicationContext->AddToFailureCache(assemblyDisplayName, hr);
980 }
981 LogExit:
982
983 BINDER_LOG_LEAVE_HR(W("AssemblyBinder::BindByName"), hr);
984 return hr;
985 }
986
987 /* static */
988 // See code:BINDER_SPACE::AssemblyBinder::GetAssembly for info on fNgenExplicitBind
989 // and fExplicitBindToNativeImage, and see code:CEECompileInfo::LoadAssemblyByPath
990 // for an example of how they're used.
991 HRESULT AssemblyBinder::BindWhereRef(ApplicationContext *pApplicationContext,
992 PathString &assemblyPath,
993 BOOL fNgenExplicitBind,
994 BOOL fExplicitBindToNativeImage,
995 bool excludeAppPaths,
996 BindResult *pBindResult)
997 {
998 HRESULT hr = S_OK;
999 BINDER_LOG_ENTER(W("AssemblyBinder::BindWhereRef"));
1000
1001 ReleaseHolder<Assembly> pAssembly;
1002 BindResult lockedBindResult;
1003
1004 // Look for already cached binding failure
1005 hr = pApplicationContext->GetFailureCache()->Lookup(assemblyPath);
1006 if (FAILED(hr))
1007 {
1008 goto LogExit;
1009 }
1010
1011 // If we return this assembly, then it is guaranteed to be not in GAC
1012 // Design decision. For now, keep the V2 model of Fusion being oblivious of the strong name.
1013 // Security team did not see any security concern with interpreting the version information.
1014 IF_FAIL_GO(GetAssembly(assemblyPath,
1015 FALSE /* fInspectionOnly */,
1016 FALSE /* fIsInGAC */,
1017
1018 // Pass through caller's intent of whether to bind to the
1019 // NI using an explicit path to the NI that was
1020 // specified. Generally only NGEN PDB generation has
1021 // this TRUE.
1022 fExplicitBindToNativeImage,
1023 &pAssembly));
1024#ifdef FEATURE_VERSIONING_LOG
1025 IF_FAIL_GO(LogAssemblyNameWhereRef(pApplicationContext, pAssembly));
1026#endif // FEATURE_VERSIONING_LOG
1027
1028 AssemblyName *pAssemblyName;
1029 pAssemblyName = pAssembly->GetAssemblyName();
1030
1031 if (!fNgenExplicitBind)
1032 {
1033 IF_FAIL_GO(BindLockedOrService(pApplicationContext,
1034 pAssemblyName,
1035 excludeAppPaths,
1036 &lockedBindResult));
1037 if (lockedBindResult.HaveResult())
1038 {
1039 pBindResult->SetResult(&lockedBindResult);
1040 GO_WITH_HRESULT(S_OK);
1041 }
1042 }
1043
1044 hr = S_OK;
1045 pAssembly->SetIsDynamicBind(TRUE);
1046 pBindResult->SetResult(pAssembly);
1047
1048 Exit:
1049
1050 if (FAILED(hr))
1051 {
1052 // Always cache binding failures
1053 hr = pApplicationContext->AddToFailureCache(assemblyPath, hr);
1054 }
1055
1056 LogExit:
1057
1058 BINDER_LOG_LEAVE_HR(W("AssemblyBinder::BindWhereRef"), hr);
1059 return hr;
1060 }
1061
1062 /* static */
1063 HRESULT AssemblyBinder::BindLocked(ApplicationContext *pApplicationContext,
1064 AssemblyName *pAssemblyName,
1065 DWORD dwBindFlags,
1066 bool excludeAppPaths,
1067 BindResult *pBindResult)
1068 {
1069 HRESULT hr = S_OK;
1070 BINDER_LOG_ENTER(W("AssemblyBinder::BindLocked"));
1071
1072 BOOL fIgnoreDynamicBinds = IgnoreDynamicBinds(dwBindFlags);
1073
1074#ifndef CROSSGEN_COMPILE
1075 ContextEntry *pContextEntry = NULL;
1076 IF_FAIL_GO(FindInExecutionContext(pApplicationContext, pAssemblyName, &pContextEntry));
1077 if (pContextEntry != NULL)
1078 {
1079 if (fIgnoreDynamicBinds && pContextEntry->GetIsDynamicBind())
1080 {
1081 // Dynamic binds need to be always considered a failure for binding closures
1082 IF_FAIL_GO(FUSION_E_APP_DOMAIN_LOCKED);
1083 }
1084#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
1085 else if (IgnoreRefDefMatch(dwBindFlags))
1086 {
1087 // Skip RefDef matching if we have been asked to.
1088 }
1089#endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
1090 else
1091 {
1092 // Can't give higher serciving than already bound
1093 IF_FAIL_GO(IsValidAssemblyVersion(pAssemblyName, pContextEntry->GetAssemblyName(), pApplicationContext));
1094 }
1095
1096 pBindResult->SetResult(pContextEntry);
1097 }
1098 else
1099#endif // !CROSSGEN_COMPILE
1100 if (pApplicationContext->IsTpaListProvided())
1101 {
1102 IF_FAIL_GO(BindByTpaList(pApplicationContext,
1103 pAssemblyName,
1104 FALSE /*fInspectionOnly*/,
1105 excludeAppPaths,
1106 pBindResult));
1107 if (pBindResult->HaveResult())
1108 {
1109 hr = IsValidAssemblyVersion(pAssemblyName, pBindResult->GetAssemblyName(), pApplicationContext);
1110 if (FAILED(hr))
1111 {
1112 pBindResult->SetNoResult();
1113 }
1114 }
1115 }
1116 Exit:
1117 BINDER_LOG_LEAVE_HR(W("AssemblyBinder::BindLocked"), hr);
1118 return hr;
1119 }
1120
1121 /* static */
1122 HRESULT AssemblyBinder::BindLockedOrService(ApplicationContext *pApplicationContext,
1123 AssemblyName *pAssemblyName,
1124 bool excludeAppPaths,
1125 BindResult *pBindResult)
1126 {
1127 HRESULT hr = S_OK;
1128 BINDER_LOG_ENTER(W("AssemblyBinder::BindLockedOrService"));
1129
1130 BindResult lockedBindResult;
1131
1132 IF_FAIL_GO(BindLocked(pApplicationContext,
1133 pAssemblyName,
1134 0 /* Do not IgnoreDynamicBinds */,
1135 excludeAppPaths,
1136 &lockedBindResult));
1137
1138 if (lockedBindResult.HaveResult())
1139 {
1140 // Locked Bind succeeded
1141 pBindResult->SetResult(&lockedBindResult);
1142 }
1143 else
1144 {
1145 pBindResult->SetNoResult();
1146 }
1147
1148 Exit:
1149 BINDER_LOG_LEAVE_HR(W("AssemblyBinder::BindLockedOrService"), hr);
1150 return hr;
1151 }
1152
1153#ifndef CROSSGEN_COMPILE
1154 /* static */
1155 HRESULT AssemblyBinder::FindInExecutionContext(ApplicationContext *pApplicationContext,
1156 AssemblyName *pAssemblyName,
1157 ContextEntry **ppContextEntry)
1158 {
1159 HRESULT hr = S_OK;
1160 BINDER_LOG_ENTER(W("AssemblyBinder::FindInExecutionContext"));
1161
1162 _ASSERTE(pApplicationContext != NULL);
1163 _ASSERTE(pAssemblyName != NULL);
1164 _ASSERTE(ppContextEntry != NULL);
1165
1166 ExecutionContext *pExecutionContext = pApplicationContext->GetExecutionContext();
1167 ContextEntry *pContextEntry = pExecutionContext->Lookup(pAssemblyName);
1168
1169 if (pContextEntry != NULL)
1170 {
1171 AssemblyName *pContextName = pContextEntry->GetAssemblyName();
1172
1173#ifdef FEATURE_VERSIONING_LOG
1174 // First-time requests are considered unlocked, everything else is locked
1175 DWORD dwLockedReason = (pContextEntry->GetIsFirstRequest() ?
1176 APP_DOMAIN_LOCKED_UNLOCKED : APP_DOMAIN_LOCKED_CONTEXT);
1177
1178 IF_FAIL_GO(LogAppDomainLocked(pApplicationContext, dwLockedReason, pContextName));
1179 pContextEntry->SetIsFirstRequest(FALSE);
1180#endif // FEATURE_VERSIONING_LOG
1181
1182 if (pAssemblyName->GetIsDefinition() &&
1183 (pContextName->GetArchitecture() != pAssemblyName->GetArchitecture()))
1184 {
1185 IF_FAIL_GO(FUSION_E_APP_DOMAIN_LOCKED);
1186 }
1187 }
1188
1189 *ppContextEntry = pContextEntry;
1190
1191 Exit:
1192 BINDER_LOG_LEAVE_HR(W("AssemblyBinder::FindInExecutionContext"), hr);
1193 return hr;
1194 }
1195
1196#endif //CROSSGEN_COMPILE
1197
1198 //
1199 // Tests whether a candidate assembly's name matches the requested.
1200 // This does not do a version check. The binder applies version policy
1201 // further up the stack once it gets a successful bind.
1202 //
1203 BOOL TestCandidateRefMatchesDef(ApplicationContext *pApplicationContext,
1204 AssemblyName *pRequestedAssemblyName,
1205 AssemblyName *pBoundAssemblyName,
1206 BOOL tpaListAssembly)
1207 {
1208 DWORD dwIncludeFlags = AssemblyName::INCLUDE_DEFAULT;
1209
1210 if (!tpaListAssembly)
1211 {
1212 SString &culture = pRequestedAssemblyName->GetCulture();
1213 if (culture.IsEmpty() || culture.EqualsCaseInsensitive(g_BinderVariables->cultureNeutral))
1214 {
1215 dwIncludeFlags |= AssemblyName::EXCLUDE_CULTURE;
1216 }
1217 }
1218
1219 if (pRequestedAssemblyName->GetArchitecture() != peNone)
1220 {
1221 dwIncludeFlags |= AssemblyName::INCLUDE_ARCHITECTURE;
1222 }
1223
1224 BINDER_LOG_ASSEMBLY_NAME(W("pBoundAssemblyName"), pBoundAssemblyName);
1225
1226 return pBoundAssemblyName->Equals(pRequestedAssemblyName, dwIncludeFlags);
1227 }
1228
1229 HRESULT BindSatelliteResourceByResourceRoots(ApplicationContext *pApplicationContext,
1230 StringArrayList *pResourceRoots,
1231 AssemblyName *pRequestedAssemblyName,
1232 BOOL fInspectionOnly,
1233 BindResult *pBindResult)
1234 {
1235 HRESULT hr = S_OK;
1236
1237 SString &simpleNameRef = pRequestedAssemblyName->GetSimpleName();
1238 SString &cultureRef = pRequestedAssemblyName->GetCulture();
1239
1240 _ASSERTE(!cultureRef.IsEmpty() && !cultureRef.EqualsCaseInsensitive(g_BinderVariables->cultureNeutral));
1241
1242 for (UINT i = 0; i < pResourceRoots->GetCount(); i++)
1243 {
1244 ReleaseHolder<Assembly> pAssembly;
1245 SString &wszBindingPath = (*pResourceRoots)[i];
1246 SString fileName(wszBindingPath);
1247
1248 CombinePath(fileName, cultureRef, fileName);
1249 CombinePath(fileName, simpleNameRef, fileName);
1250 fileName.Append(W(".dll"));
1251
1252 hr = AssemblyBinder::GetAssembly(fileName,
1253 fInspectionOnly,
1254 FALSE /* fIsInGAC */,
1255 FALSE /* fExplicitBindToNativeImage */,
1256 &pAssembly);
1257
1258 // Missing files are okay and expected when probing
1259 if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
1260 {
1261 continue;
1262 }
1263
1264 IF_FAIL_GO(hr);
1265
1266 AssemblyName *pBoundAssemblyName = pAssembly->GetAssemblyName();
1267 if (TestCandidateRefMatchesDef(pApplicationContext, pRequestedAssemblyName, pBoundAssemblyName, false /*tpaListAssembly*/))
1268 {
1269 pBindResult->SetResult(pAssembly);
1270 GO_WITH_HRESULT(S_OK);
1271 }
1272
1273#ifdef FEATURE_VERSIONING_LOG
1274 // Log the candidates we throw out for diagnostics
1275 IF_FAIL_GO(LogConfigurationError(pApplicationContext,
1276 pRequestedAssemblyName,
1277 pBoundAssemblyName));
1278#endif // FEATURE_VERSIONING_LOG
1279
1280 IF_FAIL_GO(FUSION_E_REF_DEF_MISMATCH);
1281 }
1282
1283 // Up-stack expects S_OK when we don't find any candidate assemblies and no fatal error occurred (ie, no S_FALSE)
1284 hr = S_OK;
1285 Exit:
1286 return hr;
1287 }
1288
1289 /*
1290 * BindByTpaList is the entry-point for the custom binding algorithm on the Phone.
1291 * Platform assemblies are specified as a list of files. This list is the only set of
1292 * assemblies that we will load as platform. They can be specified as IL or NIs.
1293 *
1294 * Resources for platform assemblies are located by probing starting at the Platform Resource Roots,
1295 * a set of folders configured by the host.
1296 *
1297 * If a requested assembly identity cannot be found in the TPA list or the resource roots,
1298 * it is considered an application assembly. We probe for application assemblies in one of two
1299 * sets of paths: the AppNiPaths, a list of paths containing native images, and the AppPaths, a
1300 * list of paths containing IL files and satellite resource folders.
1301 *
1302 */
1303 /* static */
1304 HRESULT AssemblyBinder::BindByTpaList(ApplicationContext *pApplicationContext,
1305 AssemblyName *pRequestedAssemblyName,
1306 BOOL fInspectionOnly,
1307 bool excludeAppPaths,
1308 BindResult *pBindResult)
1309 {
1310 HRESULT hr = S_OK;
1311 BINDER_LOG_ENTER(W("AssemblyBinder::BindByTpaList"));
1312
1313 SString &culture = pRequestedAssemblyName->GetCulture();
1314 bool fPartialMatchOnTpa = false;
1315
1316 if (!culture.IsEmpty() && !culture.EqualsCaseInsensitive(g_BinderVariables->cultureNeutral))
1317 {
1318 //
1319 // Satellite resource probing strategy is to look under each of the Platform Resource Roots
1320 // followed by App Paths.
1321 //
1322
1323 hr = BindSatelliteResourceByResourceRoots(pApplicationContext,
1324 pApplicationContext->GetPlatformResourceRoots(),
1325 pRequestedAssemblyName,
1326 fInspectionOnly,
1327 pBindResult);
1328
1329 // We found a platform resource file with matching file name, but whose ref-def didn't match. Fall
1330 // back to application resource lookup to handle case where a user creates resources with the same
1331 // names as platform ones.
1332 if (hr != FUSION_E_CONFIGURATION_ERROR)
1333 {
1334 IF_FAIL_GO(hr);
1335 }
1336
1337 if (!pBindResult->HaveResult())
1338 {
1339 IF_FAIL_GO(BindSatelliteResourceByResourceRoots(pApplicationContext,
1340 pApplicationContext->GetAppPaths(),
1341 pRequestedAssemblyName,
1342 fInspectionOnly,
1343 pBindResult));
1344 }
1345 }
1346 else
1347 {
1348 // Is assembly on TPA list?
1349 SString &simpleName = pRequestedAssemblyName->GetSimpleName();
1350 SimpleNameToFileNameMap * tpaMap = pApplicationContext->GetTpaList();
1351 const SimpleNameToFileNameMapEntry *pTpaEntry = tpaMap->LookupPtr(simpleName.GetUnicode());
1352 ReleaseHolder<Assembly> pTPAAssembly;
1353 if (pTpaEntry != nullptr)
1354 {
1355 if (pTpaEntry->m_wszNIFileName != nullptr)
1356 {
1357 SString fileName(pTpaEntry->m_wszNIFileName);
1358
1359 // A GetAssembly overload perhaps, or just another parameter to the existing method
1360 hr = GetAssembly(fileName,
1361 fInspectionOnly,
1362 TRUE, /* fIsInGAC */
1363 TRUE /* fExplicitBindToNativeImage */,
1364 &pTPAAssembly
1365 );
1366 }
1367 else
1368 {
1369 _ASSERTE(pTpaEntry->m_wszILFileName != nullptr);
1370 SString fileName(pTpaEntry->m_wszILFileName);
1371
1372 hr = GetAssembly(fileName,
1373 fInspectionOnly,
1374 TRUE, /* fIsInGAC */
1375 FALSE /* fExplicitBindToNativeImage */,
1376 &pTPAAssembly);
1377 }
1378
1379 // On file not found, simply fall back to app path probing
1380 if (hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
1381 {
1382 // Any other error is fatal
1383 IF_FAIL_GO(hr);
1384
1385 if (TestCandidateRefMatchesDef(pApplicationContext, pRequestedAssemblyName, pTPAAssembly->GetAssemblyName(), true /*tpaListAssembly*/))
1386 {
1387 // We have found the requested assembly match on TPA with validation of the full-qualified name. Bind to it.
1388 pBindResult->SetResult(pTPAAssembly);
1389 GO_WITH_HRESULT(S_OK);
1390 }
1391 else
1392 {
1393 // We found the assembly on TPA but it didnt match the RequestedAssembly assembly-name. In this case, lets proceed to see if we find the requested
1394 // assembly in the App paths.
1395 fPartialMatchOnTpa = true;
1396 }
1397 }
1398
1399 // We either didn't find a candidate, or the ref-def failed. Either way; fall back to app path probing.
1400 }
1401
1402 if (!excludeAppPaths)
1403 {
1404 // This loop executes twice max. First time through we probe AppNiPaths, the second time we probe AppPaths
1405 bool parseAppNiPaths = true;
1406 for (;;)
1407 {
1408 StringArrayList *pBindingPaths = parseAppNiPaths ? pApplicationContext->GetAppNiPaths() : pApplicationContext->GetAppPaths();
1409
1410 // Loop through the binding paths looking for a matching assembly
1411 for (DWORD i = 0; i < pBindingPaths->GetCount(); i++)
1412 {
1413 ReleaseHolder<Assembly> pAssembly;
1414 LPCWSTR wszBindingPath = (*pBindingPaths)[i];
1415
1416 SString &simpleName = pRequestedAssemblyName->GetSimpleName();
1417
1418 // Look for a matching dll first
1419 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
1420
1421 {
1422 SString fileName(wszBindingPath);
1423 CombinePath(fileName, simpleName, fileName);
1424 if (parseAppNiPaths)
1425 {
1426 fileName.Append(W(".ni.dll"));
1427 hr = GetAssembly(fileName,
1428 fInspectionOnly,
1429 FALSE, /* fIsInGAC */
1430 TRUE /* fExplicitBindToNativeImage */,
1431 &pAssembly);
1432 }
1433 else
1434 {
1435 if (FAILED(hr))
1436 {
1437 fileName.Append(W(".dll"));
1438
1439 hr = GetAssembly(fileName,
1440 fInspectionOnly,
1441 FALSE, /* fIsInGAC */
1442 FALSE /* fExplicitBindToNativeImage */,
1443 &pAssembly);
1444 }
1445 }
1446 }
1447
1448 if (FAILED(hr))
1449 {
1450 SString fileName(wszBindingPath);
1451 CombinePath(fileName, simpleName, fileName);
1452
1453 if (parseAppNiPaths)
1454 {
1455 fileName.Append(W(".ni.exe"));
1456 hr = GetAssembly(fileName,
1457 fInspectionOnly,
1458 FALSE, /* fIsInGAC */
1459 TRUE /* fExplicitBindToNativeImage */,
1460 &pAssembly);
1461 }
1462 else
1463 {
1464 if (FAILED(hr))
1465 {
1466 fileName.Append(W(".exe"));
1467
1468 hr = GetAssembly(fileName,
1469 fInspectionOnly,
1470 FALSE, /* fIsInGAC */
1471 FALSE /* fExplicitBindToNativeImage */,
1472 &pAssembly);
1473 }
1474 }
1475 }
1476
1477 // Since we're probing, file not founds are ok and we should just try another
1478 // probing path
1479 if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
1480 {
1481 continue;
1482 }
1483 IF_FAIL_GO(hr);
1484
1485 // We found a candidate.
1486 //
1487 // Below this point, we either establish that the ref-def matches, or
1488 // we fail the bind.
1489
1490 // Compare requested AssemblyName with that from the candidate assembly
1491 if (TestCandidateRefMatchesDef(pApplicationContext, pRequestedAssemblyName, pAssembly->GetAssemblyName(), false /*tpaListAssembly*/))
1492 {
1493 // At this point, we have found an assembly with the expected name in the App paths. If this was also found on TPA,
1494 // make sure that the app assembly has the same fullname (excluding version) as the TPA version. If it does, then
1495 // we should bind to the TPA assembly. If it does not, then bind to the app assembly since it has a different fullname than the
1496 // TPA assembly.
1497 if (fPartialMatchOnTpa)
1498 {
1499 if (TestCandidateRefMatchesDef(pApplicationContext, pAssembly->GetAssemblyName(), pTPAAssembly->GetAssemblyName(), true /*tpaListAssembly*/))
1500 {
1501 // Fullname (SimpleName+Culture+PKT) matched for TPA and app assembly - so bind to TPA instance.
1502 pBindResult->SetResult(pTPAAssembly);
1503 GO_WITH_HRESULT(S_OK);
1504 }
1505 else
1506 {
1507 // Fullname (SimpleName+Culture+PKT) did not match for TPA and app assembly - so bind to app instance.
1508 pBindResult->SetResult(pAssembly);
1509 GO_WITH_HRESULT(S_OK);
1510 }
1511 }
1512 else
1513 {
1514 // We didnt see this assembly on TPA - so simply bind to the app instance.
1515 pBindResult->SetResult(pAssembly);
1516 GO_WITH_HRESULT(S_OK);
1517 }
1518 }
1519
1520#ifdef FEATURE_VERSIONING_LOG
1521 // Log the candidates we throw out for diagnostics
1522 IF_FAIL_GO(LogConfigurationError(pApplicationContext,
1523 pRequestedAssemblyName,
1524 pAssembly->GetAssemblyName()));
1525#endif // FEATURE_VERSIONING_LOG
1526
1527 IF_FAIL_GO(FUSION_E_REF_DEF_MISMATCH);
1528
1529 }
1530
1531 if (!parseAppNiPaths)
1532 {
1533 break;
1534 }
1535
1536 parseAppNiPaths = false;
1537 }
1538 }
1539 }
1540
1541 // Couldn't find a matching assembly in any of the probing paths
1542 // Return S_OK here. BindByName will interpret a lack of BindResult
1543 // as a failure to find a matching assembly. Other callers of this
1544 // function, such as BindLockedOrService will interpret as deciding
1545 // not to override an explicit bind with a probed assembly
1546 hr = S_OK;
1547
1548 Exit:
1549 BINDER_LOG_LEAVE_HR(W("AssemblyBinder::BindByTpaList"), hr);
1550 return hr;
1551 }
1552
1553 /* static */
1554 HRESULT AssemblyBinder::GetAssembly(SString &assemblyPath,
1555 BOOL fInspectionOnly,
1556 BOOL fIsInGAC,
1557
1558 // When binding to the native image, should we
1559 // assume assemblyPath explicitly specifies that
1560 // NI? (If not, infer the path to the NI
1561 // implicitly.)
1562 BOOL fExplicitBindToNativeImage,
1563
1564 Assembly **ppAssembly,
1565
1566 // If assemblyPath refers to a native image without metadata,
1567 // szMDAssemblyPath gives the alternative file to get metadata.
1568 LPCTSTR szMDAssemblyPath)
1569 {
1570 HRESULT hr = S_OK;
1571
1572 BINDER_LOG_ENTER(W("Assembly::GetAssembly"));
1573 BINDER_LOG_STRING(W("assemblyPath"), assemblyPath);
1574
1575 _ASSERTE(ppAssembly != NULL);
1576
1577 ReleaseHolder<Assembly> pAssembly;
1578 ReleaseHolder<IMDInternalImport> pIMetaDataAssemblyImport;
1579 DWORD dwPAFlags[2];
1580 PEKIND PeKind = peNone;
1581 PEImage *pPEImage = NULL;
1582 PEImage *pNativePEImage = NULL;
1583
1584 // Allocate assembly object
1585 SAFE_NEW(pAssembly, Assembly);
1586
1587 // Obtain assembly meta data
1588 {
1589 LPCTSTR szAssemblyPath = const_cast<LPCTSTR>(assemblyPath.GetUnicode());
1590
1591 BINDER_LOG_ENTER(W("BinderAcquirePEImage"));
1592 hr = BinderAcquirePEImage(szAssemblyPath, &pPEImage, &pNativePEImage, fExplicitBindToNativeImage);
1593 BINDER_LOG_LEAVE_HR(W("BinderAcquirePEImage"), hr);
1594 IF_FAIL_GO(hr);
1595
1596 // If we found a native image, it might be an MSIL assembly masquerading as an native image
1597 // as a fallback mechanism for when the Triton tool chain wasn't able to generate a native image.
1598 // In that case it will not have a native header, so just treat it like the MSIL assembly it is.
1599 if (pNativePEImage)
1600 {
1601 BOOL hasHeader = TRUE;
1602 IF_FAIL_GO(BinderHasNativeHeader(pNativePEImage, &hasHeader));
1603 if (!hasHeader)
1604 {
1605 BinderReleasePEImage(pPEImage);
1606 BinderReleasePEImage(pNativePEImage);
1607
1608 BINDER_LOG_ENTER(W("BinderAcquirePEImageIL"));
1609 hr = BinderAcquirePEImage(szAssemblyPath, &pPEImage, &pNativePEImage, false);
1610 BINDER_LOG_LEAVE_HR(W("BinderAcquirePEImageIL"), hr);
1611 IF_FAIL_GO(hr);
1612 }
1613 }
1614
1615 BINDER_LOG_ENTER(W("BinderAcquireImport"));
1616 if(pNativePEImage)
1617 hr = BinderAcquireImport(pNativePEImage, &pIMetaDataAssemblyImport, dwPAFlags, TRUE);
1618 else
1619 hr = BinderAcquireImport(pPEImage, &pIMetaDataAssemblyImport, dwPAFlags, FALSE);
1620
1621 BINDER_LOG_LEAVE_HR(W("BinderAcquireImport"), hr);
1622 IF_FAIL_GO(hr);
1623
1624 if (pIMetaDataAssemblyImport == NULL && pNativePEImage != NULL)
1625 {
1626 // The native image doesn't contain metadata. Currently this is only supported for Windows.ni.winmd.
1627 // While loading Windows.winmd, CLRPrivBinderWinRT::GetAssemblyAndTryFindNativeImage should have passed
1628 // in a non-NULL szMDAssemblyPath, where we can load metadata from. If szMDAssemblyPath is NULL,
1629 // it indicates that the app is trying to load a non-WinMD assembly named Windows (it's possible
1630 // that the app happens to contain an assembly Windows.dll). To handle this case properly, we
1631 // return a file-not-found error, so the caller can continues it's search.
1632 if (szMDAssemblyPath == NULL)
1633 {
1634 IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
1635 }
1636 else
1637 {
1638 BINDER_LOG_ENTER(W("BinderAcquirePEImage"));
1639 hr = BinderAcquirePEImage(szMDAssemblyPath, &pPEImage, NULL, FALSE);
1640 BINDER_LOG_LEAVE_HR(W("BinderAcquirePEImage"), hr);
1641 IF_FAIL_GO(hr);
1642
1643 BINDER_LOG_ENTER(W("BinderAcquireImport"));
1644 hr = BinderAcquireImport(pPEImage, &pIMetaDataAssemblyImport, dwPAFlags, FALSE);
1645 BINDER_LOG_LEAVE_HR(W("BinderAcquireImport"), hr);
1646 IF_FAIL_GO(hr);
1647 }
1648 }
1649
1650 IF_FAIL_GO(TranslatePEToArchitectureType(dwPAFlags, &PeKind));
1651 }
1652
1653 // Initialize assembly object
1654 IF_FAIL_GO(pAssembly->Init(pIMetaDataAssemblyImport,
1655 PeKind,
1656 pPEImage,
1657 pNativePEImage,
1658 assemblyPath,
1659 fInspectionOnly,
1660 fIsInGAC));
1661
1662 // We're done
1663 *ppAssembly = pAssembly.Extract();
1664
1665 Exit:
1666
1667 BinderReleasePEImage(pPEImage);
1668 BinderReleasePEImage(pNativePEImage);
1669
1670 BINDER_LOG_LEAVE_HR(W("AssemblyBinder::GetAssembly"), hr);
1671
1672 // Normalize file not found
1673 if ((FAILED(hr)) && IsFileNotFound(hr))
1674 {
1675 hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
1676 }
1677
1678 return hr;
1679 }
1680
1681#ifndef CROSSGEN_COMPILE
1682
1683 /* static */
1684 HRESULT AssemblyBinder::Register(ApplicationContext *pApplicationContext,
1685 BOOL fInspectionOnly,
1686 BindResult *pBindResult)
1687 {
1688 HRESULT hr = S_OK;
1689 BINDER_LOG_ENTER(W("AssemblyBinder::Register"));
1690
1691 if (!pBindResult->GetIsContextBound())
1692 {
1693 pApplicationContext->IncrementVersion();
1694
1695 if (fInspectionOnly)
1696 {
1697 InspectionContext *pInspectionContext = pApplicationContext->GetInspectionContext();
1698 IF_FAIL_GO(pInspectionContext->Register(pBindResult));
1699 }
1700 else
1701 {
1702 // Register the bindResult in the ExecutionContext only if we dont have it already.
1703 // This method is invoked under a lock (by its caller), so we are thread safe.
1704 ContextEntry *pContextEntry = NULL;
1705 hr = FindInExecutionContext(pApplicationContext, pBindResult->GetAssemblyName(), &pContextEntry);
1706 if (hr == S_OK)
1707 {
1708 if (pContextEntry == NULL)
1709 {
1710 ExecutionContext *pExecutionContext = pApplicationContext->GetExecutionContext();
1711 IF_FAIL_GO(pExecutionContext->Register(pBindResult));
1712 }
1713 else
1714 {
1715 // The dynamic binds are compiled in CoreCLR, but they are not supported. They are only reachable by internal API Assembly.Load(byte[]) that nobody should be calling.
1716 // This code path does not handle dynamic binds correctly (and is not expected to). We do not expect to come here for dynamic binds.
1717
1718 _ASSERTE(!pContextEntry->GetIsDynamicBind());
1719
1720 // Update the BindResult with the contents of the ContextEntry we found
1721 pBindResult->SetResult(pContextEntry);
1722 }
1723 }
1724 }
1725 }
1726
1727 Exit:
1728 BINDER_LOG_LEAVE_HR(W("AssemblyBinder::Register"), hr);
1729 return hr;
1730 }
1731
1732 /* static */
1733 HRESULT AssemblyBinder::RegisterAndGetHostChosen(ApplicationContext *pApplicationContext,
1734 LONG kContextVersion,
1735 BindResult *pBindResult,
1736 BindResult *pHostBindResult)
1737 {
1738 HRESULT hr = S_OK;
1739 BINDER_LOG_ENTER(W("AssemblyBinder::RegisterHostChosen"));
1740
1741 _ASSERTE(pBindResult != NULL);
1742 _ASSERTE(pBindResult->HaveResult());
1743 _ASSERTE(pHostBindResult != NULL);
1744
1745 if (!pBindResult->GetIsContextBound())
1746 {
1747 pHostBindResult->SetResult(pBindResult);
1748
1749 {
1750 // Lock the application context
1751 CRITSEC_Holder contextLock(pApplicationContext->GetCriticalSectionCookie());
1752
1753 // Only perform costly validation if other binds succeded before us
1754 if (kContextVersion != pApplicationContext->GetVersion())
1755 {
1756 IF_FAIL_GO(AssemblyBinder::OtherBindInterfered(pApplicationContext,
1757 pBindResult));
1758
1759 if (hr == S_FALSE)
1760 {
1761 // Another bind interfered
1762 GO_WITH_HRESULT(hr);
1763 }
1764 }
1765
1766 // No bind interfered, we can now register
1767 IF_FAIL_GO(Register(pApplicationContext,
1768 FALSE /* fInspectionOnly */,
1769 pHostBindResult));
1770 }
1771 }
1772 else
1773 {
1774 // No work required. Return the input
1775 pHostBindResult->SetResult(pBindResult);
1776 }
1777
1778 Exit:
1779 BINDER_LOG_LEAVE_HR(W("AssemblyBinder::RegisterHostChosen"), hr);
1780 return hr;
1781 }
1782
1783 /* static */
1784 HRESULT AssemblyBinder::OtherBindInterfered(ApplicationContext *pApplicationContext,
1785 BindResult *pBindResult)
1786 {
1787 HRESULT hr = S_FALSE;
1788 BINDER_LOG_ENTER(W("AssemblyBinder::OtherBindInterfered"));
1789 AssemblyName *pAssemblyName = pBindResult->GetAssemblyName();
1790 PathString assemblyDisplayName;
1791
1792 _ASSERTE(pAssemblyName != NULL);
1793
1794 // Look for already cached binding failure (ignore PA, every PA will lock the context)
1795 pAssemblyName->GetDisplayName(assemblyDisplayName, AssemblyName::INCLUDE_VERSION);
1796 hr = pApplicationContext->GetFailureCache()->Lookup(assemblyDisplayName);
1797
1798 if (hr == S_OK)
1799 {
1800 ContextEntry *pContextEntry = NULL;
1801
1802 hr = FindInExecutionContext(pApplicationContext, pAssemblyName, &pContextEntry);
1803
1804 if ((hr == S_OK) && (pContextEntry == NULL))
1805 {
1806 // We can accept this bind in the domain
1807 GO_WITH_HRESULT(S_OK);
1808 }
1809 }
1810
1811 // Some other bind interfered
1812 GO_WITH_HRESULT(S_FALSE);
1813
1814 Exit:
1815 BINDER_LOG_LEAVE_HR(W("AssemblyBinder::OtherBindInterfered"), hr);
1816 return hr;
1817 }
1818
1819#endif //CROSSGEN_COMPILE
1820
1821#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
1822HRESULT AssemblyBinder::BindUsingHostAssemblyResolver (/* in */ INT_PTR pManagedAssemblyLoadContextToBindWithin,
1823 /* in */ AssemblyName *pAssemblyName,
1824 /* in */ IAssemblyName *pIAssemblyName,
1825 /* in */ CLRPrivBinderCoreCLR *pTPABinder,
1826 /* out */ Assembly **ppAssembly)
1827{
1828 HRESULT hr = E_FAIL;
1829 BINDER_LOG_ENTER(W("AssemblyBinder::BindUsingHostAssemblyResolver"));
1830
1831 _ASSERTE(pManagedAssemblyLoadContextToBindWithin != NULL);
1832
1833 // RuntimeInvokeHostAssemblyResolver will perform steps 2-4 of CLRPrivBinderAssemblyLoadContext::BindAssemblyByName.
1834 ICLRPrivAssembly *pLoadedAssembly = NULL;
1835 hr = RuntimeInvokeHostAssemblyResolver(pManagedAssemblyLoadContextToBindWithin, pIAssemblyName,
1836 pTPABinder, pAssemblyName, &pLoadedAssembly);
1837 if (SUCCEEDED(hr))
1838 {
1839 _ASSERTE(pLoadedAssembly != NULL);
1840 *ppAssembly = static_cast<Assembly *>(pLoadedAssembly);
1841 }
1842
1843 BINDER_LOG_LEAVE_HR(W("AssemblyBinder::BindUsingHostAssemblyResolver"), hr);
1844 return hr;
1845}
1846
1847/* static */
1848HRESULT AssemblyBinder::BindUsingPEImage(/* in */ ApplicationContext *pApplicationContext,
1849 /* in */ BINDER_SPACE::AssemblyName *pAssemblyName,
1850 /* in */ PEImage *pPEImage,
1851 /* in */ PEKIND peKind,
1852 /* in */ IMDInternalImport *pIMetaDataAssemblyImport,
1853 /* [retval] [out] */ Assembly **ppAssembly)
1854{
1855 HRESULT hr = E_FAIL;
1856 BINDER_LOG_ENTER(W("AssemblyBinder::BindUsingPEImage"));
1857
1858 _ASSERTE(BINDER_SPACE::fAssemblyBinderInitialized == TRUE);
1859
1860 LONG kContextVersion = 0;
1861 BindResult bindResult;
1862
1863 // Prepare binding data
1864 *ppAssembly = NULL;
1865
1866 // Attempt the actual bind (eventually more than once)
1867Retry:
1868 {
1869 // Lock the application context
1870 CRITSEC_Holder contextLock(pApplicationContext->GetCriticalSectionCookie());
1871
1872 // Attempt uncached bind and register stream if possible
1873 hr = BindByName(pApplicationContext,
1874 pAssemblyName,
1875 BIND_CACHE_FAILURES|BIND_CACHE_RERUN_BIND|BIND_IGNORE_REFDEF_MATCH,
1876 false, // excludeAppPaths
1877 &bindResult);
1878
1879 if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
1880 {
1881 IF_FAIL_GO(CreateImageAssembly(pIMetaDataAssemblyImport,
1882 peKind,
1883 pPEImage,
1884 NULL,
1885 FALSE,
1886 &bindResult));
1887
1888 }
1889 else if (hr == S_OK)
1890 {
1891 if (bindResult.HaveResult())
1892 {
1893 // Attempt was made to load an assembly that has the same name as a previously loaded one. Since same name
1894 // does not imply the same assembly, we will need to check the MVID to confirm it is the same assembly as being
1895 // requested.
1896 //
1897 GUID incomingMVID;
1898 ZeroMemory(&incomingMVID, sizeof(GUID));
1899
1900 // If we cannot get MVID, then err on side of caution and fail the
1901 // load.
1902 IF_FAIL_GO(pIMetaDataAssemblyImport->GetScopeProps(NULL, &incomingMVID));
1903
1904 GUID boundMVID;
1905 ZeroMemory(&boundMVID, sizeof(GUID));
1906
1907 // If we cannot get MVID, then err on side of caution and fail the
1908 // load.
1909 IF_FAIL_GO(bindResult.GetAsAssembly()->GetMVID(&boundMVID));
1910
1911 if (incomingMVID != boundMVID)
1912 {
1913 // MVIDs do not match, so fail the load.
1914 IF_FAIL_GO(COR_E_FILELOAD);
1915 }
1916
1917 // MVIDs match - request came in for the same assembly that was previously loaded.
1918 // Let is through...
1919 }
1920 }
1921
1922 // Remember the post-bind version of the context
1923 kContextVersion = pApplicationContext->GetVersion();
1924
1925 } // lock(pApplicationContext)
1926
1927 if (bindResult.HaveResult())
1928 {
1929 BindResult hostBindResult;
1930
1931 // This has to happen outside the binder lock as it can cause new binds
1932 IF_FAIL_GO(RegisterAndGetHostChosen(pApplicationContext,
1933 kContextVersion,
1934 &bindResult,
1935 &hostBindResult));
1936
1937 if (hr == S_FALSE)
1938 {
1939 // Another bind interfered. We need to retry entire bind.
1940 // This by design loops as long as needed because by construction we eventually
1941 // will succeed or fail the bind.
1942 bindResult.Reset();
1943 goto Retry;
1944 }
1945 else if (hr == S_OK)
1946 {
1947 *ppAssembly = hostBindResult.GetAsAssembly(TRUE /* fAddRef */);
1948 }
1949 }
1950
1951Exit:
1952
1953 BINDER_LOG_LEAVE_HR(W("AssemblyBinder::BindUsingPEImage"), hr);
1954 return hr;
1955}
1956#endif // !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
1957};
1958
1959
1960