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**
7** Header: Assembly.cpp
8**
9**
10** Purpose: Implements assembly (loader domain) architecture
11**
12**
13===========================================================*/
14
15#include "common.h"
16
17#include <stdlib.h>
18
19#include "assembly.hpp"
20#include "appdomain.hpp"
21#include "perfcounters.h"
22#include "assemblyname.hpp"
23
24
25
26#include "eeprofinterfaces.h"
27#include "reflectclasswriter.h"
28#include "comdynamic.h"
29
30#include <wincrypt.h>
31#include "urlmon.h"
32#include "sha1.h"
33
34#include "eeconfig.h"
35#include "strongname.h"
36
37#include "ceefilegenwriter.h"
38#include "assemblynative.hpp"
39#include "threadsuspend.h"
40
41#ifdef FEATURE_PREJIT
42#include "corcompile.h"
43#endif
44
45#include "appdomainnative.hpp"
46#include "customattribute.h"
47#include "winnls.h"
48
49#include "caparser.h"
50#include "../md/compiler/custattr.h"
51#include "mdaassistants.h"
52
53#include "peimagelayout.inl"
54
55
56// Define these macro's to do strict validation for jit lock and class init entry leaks.
57// This defines determine if the asserts that verify for these leaks are defined or not.
58// These asserts can sometimes go off even if no entries have been leaked so this defines
59// should be used with caution.
60//
61// If we are inside a .cctor when the application shut's down then the class init lock's
62// head will be set and this will cause the assert to go off.,
63//
64// If we are jitting a method when the application shut's down then the jit lock's head
65// will be set causing the assert to go off.
66
67//#define STRICT_JITLOCK_ENTRY_LEAK_DETECTION
68//#define STRICT_CLSINITLOCK_ENTRY_LEAK_DETECTION
69
70
71#ifndef DACCESS_COMPILE
72
73// This value is to make it easier to diagnose Assembly Loader "grant set" crashes.
74// See Dev11 bug 358184 for more details.
75
76// This value is not thread safe and is not intended to be. It is just a best
77// effort to collect more data on the problem. Is is possible, though unlikely,
78// that thread A would record a reason for an upcoming crash,
79// thread B would then record a different reason, and we would then
80// crash on thread A, thus ending up with the recorded reason not matching
81// the thread we crash in. Be aware of this when using this value
82// to help your debugging.
83DWORD g_dwLoaderReasonForNotSharing = 0; // See code:DomainFile::m_dwReasonForRejectingNativeImage for a similar variable.
84
85// These will sometimes result in a crash with error code 0x80131401 SECURITY_E_INCOMPATIBLE_SHARE
86// "Loading this assembly would produce a different grant set from other instances."
87enum ReasonForNotSharing
88{
89 ReasonForNotSharing_NoInfoRecorded = 0x1,
90 ReasonForNotSharing_NullDomainassembly = 0x2,
91 ReasonForNotSharing_DebuggerFlagMismatch = 0x3,
92 ReasonForNotSharing_NullPeassembly = 0x4,
93 ReasonForNotSharing_MissingAssemblyClosure1 = 0x5,
94 ReasonForNotSharing_MissingAssemblyClosure2 = 0x6,
95 ReasonForNotSharing_MissingDependenciesResolved = 0x7,
96 ReasonForNotSharing_ClosureComparisonFailed = 0x8,
97};
98
99#define NO_FRIEND_ASSEMBLIES_MARKER ((FriendAssemblyDescriptor *)S_FALSE)
100
101//----------------------------------------------------------------------------------------------
102// The ctor's job is to initialize the Assembly enough so that the dtor can safely run.
103// It cannot do any allocations or operations that might fail. Those operations should be done
104// in Assembly::Init()
105//----------------------------------------------------------------------------------------------
106Assembly::Assembly(BaseDomain *pDomain, PEAssembly* pFile, DebuggerAssemblyControlFlags debuggerFlags, BOOL fIsCollectible) :
107 m_pDomain(pDomain),
108 m_pClassLoader(NULL),
109 m_pEntryPoint(NULL),
110 m_pManifest(NULL),
111 m_pManifestFile(clr::SafeAddRef(pFile)),
112 m_pFriendAssemblyDescriptor(NULL),
113 m_isDynamic(false),
114#ifdef FEATURE_COLLECTIBLE_TYPES
115 m_isCollectible(fIsCollectible),
116#endif
117 m_nextAvailableModuleIndex(1),
118 m_pLoaderAllocator(NULL),
119 m_isDisabledPrivateReflection(0),
120#ifdef FEATURE_COMINTEROP
121 m_pITypeLib(NULL),
122 m_winMDStatus(WinMDStatus_Unknown),
123 m_pManifestWinMDImport(NULL),
124#endif // FEATURE_COMINTEROP
125 m_debuggerFlags(debuggerFlags),
126 m_fTerminated(FALSE)
127#ifdef FEATURE_COMINTEROP
128 , m_InteropAttributeStatus(INTEROP_ATTRIBUTE_UNSET)
129#endif
130#ifdef FEATURE_PREJIT
131 , m_isInstrumentedStatus(IS_INSTRUMENTED_UNSET)
132#endif
133{
134 STANDARD_VM_CONTRACT;
135}
136
137// This name needs to stay in sync with AssemblyBuilder.ManifestModuleName
138// which is used in AssemblyBuilder.InitManifestModule
139#define REFEMIT_MANIFEST_MODULE_NAME W("RefEmit_InMemoryManifestModule")
140
141
142//----------------------------------------------------------------------------------------------
143// Does most Assembly initialization tasks. It can assume the ctor has already run
144// and the assembly is safely destructable. Whether this function throws or succeeds,
145// it must leave the Assembly in a safely destructable state.
146//----------------------------------------------------------------------------------------------
147void Assembly::Init(AllocMemTracker *pamTracker, LoaderAllocator *pLoaderAllocator)
148{
149 STANDARD_VM_CONTRACT;
150
151 if (IsSystem())
152 {
153 _ASSERTE(pLoaderAllocator == NULL); // pLoaderAllocator may only be non-null for collectible types
154 m_pLoaderAllocator = SystemDomain::GetGlobalLoaderAllocator();
155 }
156 else
157 {
158 if (!IsCollectible())
159 {
160 // pLoaderAllocator will only be non-null for reflection emit assemblies
161 _ASSERTE((pLoaderAllocator == NULL) || (pLoaderAllocator == GetDomain()->AsAppDomain()->GetLoaderAllocator()));
162 m_pLoaderAllocator = GetDomain()->AsAppDomain()->GetLoaderAllocator();
163 }
164 else
165 {
166 _ASSERTE(pLoaderAllocator != NULL); // ppLoaderAllocator must be non-null for collectible assemblies
167
168 m_pLoaderAllocator = pLoaderAllocator;
169 }
170 }
171 _ASSERTE(m_pLoaderAllocator != NULL);
172
173 m_pClassLoader = new ClassLoader(this);
174 m_pClassLoader->Init(pamTracker);
175
176 COUNTER_ONLY(GetPerfCounters().m_Loading.cAssemblies++);
177
178#ifndef CROSSGEN_COMPILE
179 if (GetManifestFile()->IsDynamic())
180 // manifest modules of dynamic assemblies are always transient
181 m_pManifest = ReflectionModule::Create(this, GetManifestFile(), pamTracker, REFEMIT_MANIFEST_MODULE_NAME, TRUE);
182 else
183#endif
184 m_pManifest = Module::Create(this, mdFileNil, GetManifestFile(), pamTracker);
185
186 PrepareModuleForAssembly(m_pManifest, pamTracker);
187
188 CacheManifestFiles();
189
190 if (!m_pManifest->IsReadyToRun())
191 CacheManifestExportedTypes(pamTracker);
192
193
194 // Check for the assemblies that contain SIMD Vector types.
195 // If we encounter a non-trusted assembly with these names, we will simply not recognize any of its
196 // methods as intrinsics.
197 LPCUTF8 assemblyName = GetSimpleName();
198 const int length = sizeof("System.Numerics") - 1;
199 if ((strncmp(assemblyName, "System.Numerics", length) == 0) &&
200 ((assemblyName[length] == '\0') || (strcmp(assemblyName+length, ".Vectors") == 0)))
201 {
202 m_fIsSIMDVectorAssembly = true;
203 }
204 else
205 {
206 m_fIsSIMDVectorAssembly = false;
207 }
208
209 // We'll load the friend assembly information lazily. For the ngen case we should avoid
210 // loading it entirely.
211 //CacheFriendAssemblyInfo();
212
213 {
214 CANNOTTHROWCOMPLUSEXCEPTION();
215 FAULT_FORBID();
216 //Cannot fail after this point.
217
218 PublishModuleIntoAssembly(m_pManifest);
219
220 return; // Explicit return to let you know you are NOT welcome to add code after the CANNOTTHROW/FAULT_FORBID expires
221 }
222}
223
224BOOL Assembly::IsDisabledPrivateReflection()
225{
226 CONTRACTL
227 {
228 THROWS;
229 }
230 CONTRACTL_END;
231
232 enum { UNINITIALIZED, ENABLED, DISABLED};
233
234 if (m_isDisabledPrivateReflection == UNINITIALIZED)
235 {
236 IMDInternalImport *pImport = GetManifestImport();
237 HRESULT hr = pImport->GetCustomAttributeByName(GetManifestToken(), DISABLED_PRIVATE_REFLECTION_TYPE, NULL, 0);
238 IfFailThrow(hr);
239
240 if (hr == S_OK)
241 {
242 m_isDisabledPrivateReflection = DISABLED;
243 }
244 else
245 {
246 m_isDisabledPrivateReflection = ENABLED;
247 }
248 }
249
250 return m_isDisabledPrivateReflection == DISABLED;
251}
252
253#ifndef CROSSGEN_COMPILE
254Assembly::~Assembly()
255{
256 CONTRACTL
257 {
258 NOTHROW;
259 GC_TRIGGERS;
260 DISABLED(FORBID_FAULT); //Must clean up some profiler stuff
261 }
262 CONTRACTL_END
263
264 Terminate();
265
266 if (m_pFriendAssemblyDescriptor != NULL && m_pFriendAssemblyDescriptor != NO_FRIEND_ASSEMBLIES_MARKER)
267 delete m_pFriendAssemblyDescriptor;
268
269 if (m_pManifestFile)
270 {
271 m_pManifestFile->Release();
272 }
273
274#ifdef FEATURE_COMINTEROP
275 if (m_pManifestWinMDImport)
276 {
277 m_pManifestWinMDImport->Release();
278 }
279
280 if (m_pITypeLib != nullptr && m_pITypeLib != Assembly::InvalidTypeLib)
281 {
282 m_pITypeLib->Release();
283 }
284#endif // FEATURE_COMINTEROP
285}
286
287#ifdef FEATURE_PREJIT
288void Assembly::DeleteNativeCodeRanges()
289{
290 CONTRACTL
291 {
292 NOTHROW;
293 GC_NOTRIGGER;
294 MODE_PREEMPTIVE;
295 FORBID_FAULT;
296 }
297 CONTRACTL_END
298
299 ModuleIterator i = IterateModules();
300 while (i.Next())
301 i.GetModule()->DeleteNativeCodeRanges();
302}
303#endif
304
305#ifdef PROFILING_SUPPORTED
306void ProfilerCallAssemblyUnloadStarted(Assembly* assemblyUnloaded)
307{
308 WRAPPER_NO_CONTRACT;
309 {
310 BEGIN_PIN_PROFILER(CORProfilerPresent());
311 GCX_PREEMP();
312 g_profControlBlock.pProfInterface->AssemblyUnloadStarted((AssemblyID)assemblyUnloaded);
313 END_PIN_PROFILER();
314 }
315}
316
317void ProfilerCallAssemblyUnloadFinished(Assembly* assemblyUnloaded)
318{
319 WRAPPER_NO_CONTRACT;
320 {
321 BEGIN_PIN_PROFILER(CORProfilerPresent());
322 GCX_PREEMP();
323 g_profControlBlock.pProfInterface->AssemblyUnloadFinished((AssemblyID) assemblyUnloaded, S_OK);
324 END_PIN_PROFILER();
325 }
326}
327#endif
328
329void Assembly::StartUnload()
330{
331 STATIC_CONTRACT_NOTHROW;
332 STATIC_CONTRACT_GC_TRIGGERS;
333 STATIC_CONTRACT_FORBID_FAULT;
334#ifdef PROFILING_SUPPORTED
335 if (CORProfilerTrackAssemblyLoads())
336 {
337 ProfilerCallAssemblyUnloadStarted(this);
338 }
339#endif
340}
341
342void Assembly::Terminate( BOOL signalProfiler )
343{
344 STATIC_CONTRACT_NOTHROW;
345 STATIC_CONTRACT_GC_TRIGGERS;
346
347 STRESS_LOG1(LF_LOADER, LL_INFO100, "Assembly::Terminate (this = 0x%p)\n", reinterpret_cast<void *>(this));
348
349 if (this->m_fTerminated)
350 return;
351
352 if (m_pClassLoader != NULL)
353 {
354 GCX_PREEMP();
355 delete m_pClassLoader;
356 m_pClassLoader = NULL;
357 }
358
359 COUNTER_ONLY(GetPerfCounters().m_Loading.cAssemblies--);
360
361#ifdef PROFILING_SUPPORTED
362 if (CORProfilerTrackAssemblyLoads())
363 {
364 ProfilerCallAssemblyUnloadFinished(this);
365 }
366#endif // PROFILING_SUPPORTED
367
368 this->m_fTerminated = TRUE;
369}
370#endif // CROSSGEN_COMPILE
371
372Assembly * Assembly::Create(
373 BaseDomain * pDomain,
374 PEAssembly * pFile,
375 DebuggerAssemblyControlFlags debuggerFlags,
376 BOOL fIsCollectible,
377 AllocMemTracker * pamTracker,
378 LoaderAllocator * pLoaderAllocator)
379{
380 STANDARD_VM_CONTRACT;
381
382 NewHolder<Assembly> pAssembly (new Assembly(pDomain, pFile, debuggerFlags, fIsCollectible));
383
384 // If there are problems that arise from this call stack, we'll chew up a lot of stack
385 // with the various EX_TRY/EX_HOOKs that we will encounter.
386 INTERIOR_STACK_PROBE_FOR(GetThread(), DEFAULT_ENTRY_PROBE_SIZE);
387#ifdef PROFILING_SUPPORTED
388 {
389 BEGIN_PIN_PROFILER(CORProfilerTrackAssemblyLoads());
390 GCX_COOP();
391 g_profControlBlock.pProfInterface->AssemblyLoadStarted((AssemblyID)(Assembly *) pAssembly);
392 END_PIN_PROFILER();
393 }
394
395 // Need TRY/HOOK instead of holder so we can get HR of exception thrown for profiler callback
396 EX_TRY
397#endif
398 {
399 pAssembly->Init(pamTracker, pLoaderAllocator);
400 }
401#ifdef PROFILING_SUPPORTED
402 EX_HOOK
403 {
404 {
405 BEGIN_PIN_PROFILER(CORProfilerTrackAssemblyLoads());
406 GCX_COOP();
407 g_profControlBlock.pProfInterface->AssemblyLoadFinished((AssemblyID)(Assembly *) pAssembly,
408 GET_EXCEPTION()->GetHR());
409 END_PIN_PROFILER();
410 }
411 }
412 EX_END_HOOK;
413#endif
414 pAssembly.SuppressRelease();
415 END_INTERIOR_STACK_PROBE;
416
417 return pAssembly;
418} // Assembly::Create
419
420
421#ifndef CROSSGEN_COMPILE
422Assembly *Assembly::CreateDynamic(AppDomain *pDomain, CreateDynamicAssemblyArgs *args)
423{
424 // WARNING: not backout clean
425 CONTRACT(Assembly *)
426 {
427 THROWS;
428 GC_TRIGGERS;
429 INJECT_FAULT(COMPlusThrowOM(););
430 MODE_COOPERATIVE;
431 PRECONDITION(CheckPointer(args));
432 }
433 CONTRACT_END;
434
435 // This must be before creation of the AllocMemTracker so that the destructor for the AllocMemTracker happens before the destructor for pLoaderAllocator.
436 // That is necessary as the allocation of Assembly objects and other related details is done on top of heaps located in
437 // the loader allocator objects.
438 NewHolder<LoaderAllocator> pLoaderAllocator;
439
440 AllocMemTracker amTracker;
441 AllocMemTracker *pamTracker = &amTracker;
442
443 Assembly *pRetVal = NULL;
444
445 AppDomain *pCallersDomain;
446 MethodDesc *pmdEmitter = SystemDomain::GetCallersMethod(args->stackMark, &pCallersDomain);
447
448 // Called either from interop or async delegate invocation. Rejecting because we don't
449 // know how to set the correct permission on the new dynamic assembly.
450 if (!pmdEmitter)
451 COMPlusThrow(kInvalidOperationException);
452
453 Assembly *pCallerAssembly = pmdEmitter->GetAssembly();
454
455 // First, we set up a pseudo-manifest file for the assembly.
456
457 // Set up the assembly name
458
459 STRINGREF strRefName = (STRINGREF) args->assemblyName->GetSimpleName();
460
461 if (strRefName == NULL)
462 COMPlusThrow(kArgumentException, W("ArgumentNull_AssemblyNameName"));
463
464 StackSString name;
465 strRefName->GetSString(name);
466
467 if (name.GetCount() == 0)
468 COMPlusThrow(kArgumentException, W("ArgumentNull_AssemblyNameName"));
469
470 SString::Iterator i = name.Begin();
471 if (COMCharacter::nativeIsWhiteSpace(*i)
472 || name.Find(i, '\\')
473 || name.Find(i, ':')
474 || name.Find(i, '/'))
475 {
476 COMPlusThrow(kArgumentException, W("Argument_InvalidAssemblyName"));
477 }
478
479 // Set up the assembly manifest metadata
480 // When we create dynamic assembly, we always use a working copy of IMetaDataAssemblyEmit
481 // to store temporary runtime assembly information. This is to preserve the invariant that
482 // an assembly must have a PEFile with proper metadata.
483 // This working copy of IMetaDataAssemblyEmit will store every AssemblyRef as a simple name
484 // reference as we must have an instance of Assembly(can be dynamic assembly) before we can
485 // add such a reference. Also because the referenced assembly if dynamic strong name, it may
486 // not be ready to be hashed!
487
488 SafeComHolder<IMetaDataAssemblyEmit> pAssemblyEmit;
489 PEFile::DefineEmitScope(
490 IID_IMetaDataAssemblyEmit,
491 &pAssemblyEmit);
492
493 // remember the hash algorithm
494 ULONG ulHashAlgId = args->assemblyName->GetAssemblyHashAlgorithm();
495 if (ulHashAlgId == 0)
496 ulHashAlgId = CALG_SHA1;
497
498 ASSEMBLYMETADATA assemData;
499 memset(&assemData, 0, sizeof(assemData));
500
501 // get the version info (default to 0.0.0.0 if none)
502 VERSIONREF versionRef = (VERSIONREF) args->assemblyName->GetVersion();
503 if (versionRef != NULL)
504 {
505 assemData.usMajorVersion = (USHORT)versionRef->GetMajor();
506 assemData.usMinorVersion = (USHORT)versionRef->GetMinor();
507 assemData.usBuildNumber = (USHORT)versionRef->GetBuild();
508 assemData.usRevisionNumber = (USHORT)versionRef->GetRevision();
509 }
510
511 struct _gc
512 {
513 OBJECTREF cultureinfo;
514 STRINGREF pString;
515 OBJECTREF orArrayOrContainer;
516 OBJECTREF throwable;
517 OBJECTREF strongNameKeyPair;
518 } gc;
519 ZeroMemory(&gc, sizeof(gc));
520
521 GCPROTECT_BEGIN(gc);
522
523 StackSString culture;
524
525 gc.cultureinfo = args->assemblyName->GetCultureInfo();
526 if (gc.cultureinfo != NULL)
527 {
528 MethodDescCallSite getName(METHOD__CULTURE_INFO__GET_NAME, &gc.cultureinfo);
529
530 ARG_SLOT args2[] =
531 {
532 ObjToArgSlot(gc.cultureinfo)
533 };
534
535 // convert culture info into a managed string form
536 gc.pString = getName.Call_RetSTRINGREF(args2);
537 gc.pString->GetSString(culture);
538
539 assemData.szLocale = (LPWSTR) (LPCWSTR) culture;
540 }
541
542 SBuffer publicKey;
543 if (args->assemblyName->GetPublicKey() != NULL)
544 {
545 publicKey.Set(args->assemblyName->GetPublicKey()->GetDataPtr(),
546 args->assemblyName->GetPublicKey()->GetNumComponents());
547 }
548
549
550 // get flags
551 DWORD dwFlags = args->assemblyName->GetFlags();
552
553 // Now create a dynamic PE file out of the name & metadata
554 PEAssemblyHolder pFile;
555
556 {
557 GCX_PREEMP();
558
559 mdAssembly ma;
560 IfFailThrow(pAssemblyEmit->DefineAssembly(publicKey, publicKey.GetSize(), ulHashAlgId,
561 name, &assemData, dwFlags,
562 &ma));
563 pFile = PEAssembly::Create(pCallerAssembly->GetManifestFile(), pAssemblyEmit);
564
565 // Dynamically created modules (aka RefEmit assemblies) do not have a LoadContext associated with them since they are not bound
566 // using an actual binder. As a result, we will assume the same binding/loadcontext information for the dynamic assembly as its
567 // caller/creator to ensure that any assembly loads triggered by the dynamic assembly are resolved using the intended load context.
568 //
569 // If the creator assembly has a HostAssembly associated with it, then use it for binding. Otherwise, the creator is dynamic
570 // and will have a fallback load context binder associated with it.
571 ICLRPrivBinder *pFallbackLoadContextBinder = nullptr;
572
573 // There is always a manifest file - wehther working with static or dynamic assemblies.
574 PEFile *pCallerAssemblyManifestFile = pCallerAssembly->GetManifestFile();
575 _ASSERTE(pCallerAssemblyManifestFile != NULL);
576
577 if (!pCallerAssemblyManifestFile->IsDynamic())
578 {
579 // Static assemblies with do not have fallback load context
580 _ASSERTE(pCallerAssemblyManifestFile->GetFallbackLoadContextBinder() == nullptr);
581
582 if (pCallerAssemblyManifestFile->IsSystem())
583 {
584 // CoreLibrary is always bound to TPA binder
585 pFallbackLoadContextBinder = pDomain->GetTPABinderContext();
586 }
587 else
588 {
589 // Fetch the binder from the host assembly
590 PTR_ICLRPrivAssembly pCallerAssemblyHostAssembly = pCallerAssemblyManifestFile->GetHostAssembly();
591 _ASSERTE(pCallerAssemblyHostAssembly != nullptr);
592
593 UINT_PTR assemblyBinderID = 0;
594 IfFailThrow(pCallerAssemblyHostAssembly->GetBinderID(&assemblyBinderID));
595 pFallbackLoadContextBinder = reinterpret_cast<ICLRPrivBinder *>(assemblyBinderID);
596 }
597 }
598 else
599 {
600 // Creator assembly is dynamic too, so use its fallback load context for the one
601 // we are creating.
602 pFallbackLoadContextBinder = pCallerAssemblyManifestFile->GetFallbackLoadContextBinder();
603 }
604
605 // At this point, we should have a fallback load context binder to work with
606 _ASSERTE(pFallbackLoadContextBinder != nullptr);
607
608 // Set it as the fallback load context binder for the dynamic assembly being created
609 pFile->SetFallbackLoadContextBinder(pFallbackLoadContextBinder);
610 }
611
612 NewHolder<DomainAssembly> pDomainAssembly;
613
614 {
615 GCX_PREEMP();
616
617 // Create a new LoaderAllocator if appropriate
618 if ((args->access & ASSEMBLY_ACCESS_COLLECT) != 0)
619 {
620 AssemblyLoaderAllocator *pAssemblyLoaderAllocator = new AssemblyLoaderAllocator();
621 pAssemblyLoaderAllocator->SetCollectible();
622 pLoaderAllocator = pAssemblyLoaderAllocator;
623
624 // Some of the initialization functions are not virtual. Call through the derived class
625 // to prevent calling the base class version.
626 pAssemblyLoaderAllocator->Init(pDomain);
627
628 // Setup the managed proxy now, but do not actually transfer ownership to it.
629 // Once everything is setup and nothing can fail anymore, the ownership will be
630 // atomically transfered by call to LoaderAllocator::ActivateManagedTracking().
631 pAssemblyLoaderAllocator->SetupManagedTracking(&args->loaderAllocator);
632 }
633 else
634 {
635 pLoaderAllocator = pDomain->GetLoaderAllocator();
636 pLoaderAllocator.SuppressRelease();
637 }
638
639 // Create a domain assembly
640 pDomainAssembly = new DomainAssembly(pDomain, pFile, pLoaderAllocator);
641 if (pDomainAssembly->IsCollectible())
642 {
643 // We add the assembly to the LoaderAllocator only when we are sure that it can be added
644 // and won't be deleted in case of a concurrent load from the same ALC
645 ((AssemblyLoaderAllocator *)(LoaderAllocator *)pLoaderAllocator)->AddDomainAssembly(pDomainAssembly);
646 }
647 }
648
649 // Start loading process
650 {
651 // Create a concrete assembly
652 // (!Do not remove scoping brace: order is important here: the Assembly holder must destruct before the AllocMemTracker!)
653 NewHolder<Assembly> pAssem;
654
655 {
656 GCX_PREEMP();
657 // Assembly::Create will call SuppressRelease on the NewHolder that holds the LoaderAllocator when it transfers ownership
658 pAssem = Assembly::Create(pDomain, pFile, pDomainAssembly->GetDebuggerInfoBits(), args->access & ASSEMBLY_ACCESS_COLLECT ? TRUE : FALSE, pamTracker, pLoaderAllocator);
659
660 ReflectionModule* pModule = (ReflectionModule*) pAssem->GetManifestModule();
661 pModule->SetCreatingAssembly( pCallerAssembly );
662
663
664 if ((args->access & ASSEMBLY_ACCESS_COLLECT) != 0)
665 {
666 // Initializing the virtual call stub manager is delayed to remove the need for the LoaderAllocator destructor to properly handle
667 // uninitializing the VSD system. (There is a need to suspend the runtime, and that's tricky)
668 pLoaderAllocator->InitVirtualCallStubManager(pDomain);
669 }
670 }
671
672 pAssem->m_isDynamic = true;
673
674 //we need to suppress release for pAssem to avoid double release
675 pAssem.SuppressRelease ();
676
677 {
678 GCX_PREEMP();
679
680 // Finish loading process
681 // <TODO> would be REALLY nice to unify this with main loading loop </TODO>
682 pDomainAssembly->Begin();
683 pDomainAssembly->SetAssembly(pAssem);
684 pDomainAssembly->m_level = FILE_LOAD_ALLOCATE;
685 pDomainAssembly->DeliverSyncEvents();
686 pDomainAssembly->DeliverAsyncEvents();
687 pDomainAssembly->FinishLoad();
688 pDomainAssembly->ClearLoading();
689 pDomainAssembly->m_level = FILE_ACTIVE;
690 }
691
692 {
693 CANNOTTHROWCOMPLUSEXCEPTION();
694 FAULT_FORBID();
695
696 //Cannot fail after this point
697
698 pDomainAssembly.SuppressRelease(); // This also effectively suppresses the release of the pAssem
699 pamTracker->SuppressRelease();
700
701 // Once we reach this point, the loader allocator lifetime is controlled by the Assembly object.
702 if ((args->access & ASSEMBLY_ACCESS_COLLECT) != 0)
703 {
704 // Atomically transfer ownership to the managed heap
705 pLoaderAllocator->ActivateManagedTracking();
706 pLoaderAllocator.SuppressRelease();
707 }
708
709 pAssem->SetIsTenured();
710 pRetVal = pAssem;
711 }
712 }
713 GCPROTECT_END();
714
715 RETURN pRetVal;
716} // Assembly::CreateDynamic
717
718
719#endif // CROSSGEN_COMPILE
720
721void Assembly::SetDomainAssembly(DomainAssembly *pDomainAssembly)
722{
723 CONTRACTL
724 {
725 PRECONDITION(CheckPointer(pDomainAssembly));
726 THROWS;
727 GC_TRIGGERS;
728 INJECT_FAULT(COMPlusThrowOM(););
729 }
730 CONTRACTL_END;
731
732 GetManifestModule()->SetDomainFile(pDomainAssembly);
733
734} // Assembly::SetDomainAssembly
735
736#endif // #ifndef DACCESS_COMPILE
737
738DomainAssembly *Assembly::GetDomainAssembly(AppDomain *pDomain)
739{
740 CONTRACT(DomainAssembly *)
741 {
742 PRECONDITION(CheckPointer(pDomain, NULL_NOT_OK));
743 POSTCONDITION(CheckPointer(RETVAL));
744 THROWS;
745 GC_TRIGGERS;
746 }
747 CONTRACT_END;
748
749 RETURN GetManifestModule()->GetDomainAssembly(pDomain);
750}
751
752DomainAssembly *Assembly::FindDomainAssembly(AppDomain *pDomain)
753{
754 CONTRACT(DomainAssembly *)
755 {
756 PRECONDITION(CheckPointer(pDomain));
757 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
758 NOTHROW;
759 GC_NOTRIGGER;
760 FORBID_FAULT;
761 SO_TOLERANT;
762 SUPPORTS_DAC;
763 }
764 CONTRACT_END;
765
766 PREFIX_ASSUME (GetManifestModule() !=NULL);
767 RETURN GetManifestModule()->FindDomainAssembly(pDomain);
768}
769
770PTR_LoaderHeap Assembly::GetLowFrequencyHeap()
771{
772 WRAPPER_NO_CONTRACT;
773
774 return GetLoaderAllocator()->GetLowFrequencyHeap();
775}
776
777PTR_LoaderHeap Assembly::GetHighFrequencyHeap()
778{
779 WRAPPER_NO_CONTRACT;
780
781 return GetLoaderAllocator()->GetHighFrequencyHeap();
782}
783
784
785PTR_LoaderHeap Assembly::GetStubHeap()
786{
787 WRAPPER_NO_CONTRACT;
788
789 return GetLoaderAllocator()->GetStubHeap();
790}
791
792
793PTR_BaseDomain Assembly::GetDomain()
794{
795 LIMITED_METHOD_CONTRACT;
796 SUPPORTS_DAC;
797
798 _ASSERTE(m_pDomain);
799 return (m_pDomain);
800}
801
802#ifndef DACCESS_COMPILE
803
804void Assembly::SetParent(BaseDomain* pParent)
805{
806 LIMITED_METHOD_CONTRACT;
807
808 m_pDomain = pParent;
809}
810
811#endif // !DACCCESS_COMPILE
812
813mdFile Assembly::GetManifestFileToken(LPCSTR name)
814{
815
816 return mdFileNil;
817}
818
819mdFile Assembly::GetManifestFileToken(IMDInternalImport *pImport, mdFile kFile)
820{
821 WRAPPER_NO_CONTRACT;
822 SUPPORTS_DAC;
823
824 LPCSTR name;
825 if ((TypeFromToken(kFile) != mdtFile) ||
826 !pImport->IsValidToken(kFile))
827 {
828 BAD_FORMAT_NOTHROW_ASSERT(!"Invalid File token");
829 return mdTokenNil;
830 }
831
832 if (FAILED(pImport->GetFileProps(kFile, &name, NULL, NULL, NULL)))
833 {
834 BAD_FORMAT_NOTHROW_ASSERT(!"Invalid File token");
835 return mdTokenNil;
836 }
837
838 return GetManifestFileToken(name);
839}
840
841Module *Assembly::FindModuleByExportedType(mdExportedType mdType,
842 Loader::LoadFlag loadFlag,
843 mdTypeDef mdNested,
844 mdTypeDef* pCL)
845{
846 CONTRACT(Module *)
847 {
848 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
849 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
850 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else INJECT_FAULT(COMPlusThrowOM(););
851 MODE_ANY;
852 POSTCONDITION(CheckPointer(RETVAL, loadFlag==Loader::Load ? NULL_NOT_OK : NULL_OK));
853 SUPPORTS_DAC;
854 }
855 CONTRACT_END
856
857 mdToken mdLinkRef;
858 mdToken mdBinding;
859
860 IMDInternalImport *pManifestImport = GetManifestImport();
861
862 IfFailThrow(pManifestImport->GetExportedTypeProps(
863 mdType,
864 NULL,
865 NULL,
866 &mdLinkRef, // Impl
867 &mdBinding, // Hint
868 NULL)); // dwflags
869
870 // Don't trust the returned tokens.
871 if (!pManifestImport->IsValidToken(mdLinkRef))
872 {
873 if (loadFlag != Loader::Load)
874 {
875 RETURN NULL;
876 }
877 else
878 {
879 ThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN);
880 }
881 }
882
883 switch(TypeFromToken(mdLinkRef)) {
884 case mdtAssemblyRef:
885 {
886 *pCL = mdTypeDefNil; // We don't trust the mdBinding token
887
888 Assembly *pAssembly = NULL;
889 switch(loadFlag)
890 {
891 case Loader::Load:
892 {
893#ifndef DACCESS_COMPILE
894 // LoadAssembly never returns NULL
895 DomainAssembly * pDomainAssembly =
896 GetManifestModule()->LoadAssembly(::GetAppDomain(), mdLinkRef);
897 PREFIX_ASSUME(pDomainAssembly != NULL);
898
899 RETURN pDomainAssembly->GetCurrentModule();
900#else
901 _ASSERTE(!"DAC shouldn't attempt to trigger loading");
902 return NULL;
903#endif // !DACCESS_COMPILE
904 };
905 case Loader::DontLoad:
906 pAssembly = GetManifestModule()->GetAssemblyIfLoaded(mdLinkRef);
907 break;
908 case Loader::SafeLookup:
909 pAssembly = GetManifestModule()->LookupAssemblyRef(mdLinkRef);
910 break;
911 default:
912 _ASSERTE(FALSE);
913 }
914
915 if (pAssembly)
916 RETURN pAssembly->GetManifestModule();
917 else
918 RETURN NULL;
919
920 }
921
922 case mdtFile:
923 {
924 // We may not want to trust this TypeDef token, since it
925 // was saved in a scope other than the one it was defined in
926 if (mdNested == mdTypeDefNil)
927 *pCL = mdBinding;
928 else
929 *pCL = mdNested;
930
931 // Note that we don't want to attempt a LoadModule if a GetModuleIfLoaded will
932 // succeed, because it has a stronger contract.
933 Module *pModule = GetManifestModule()->GetModuleIfLoaded(mdLinkRef, TRUE, FALSE);
934#ifdef DACCESS_COMPILE
935 return pModule;
936#else
937 if (pModule != NULL)
938 RETURN pModule;
939
940 if(loadFlag==Loader::SafeLookup)
941 return NULL;
942
943 // We should never get here in the GC case - the above should have succeeded.
944 CONSISTENCY_CHECK(!FORBIDGC_LOADER_USE_ENABLED());
945
946 DomainFile * pDomainModule = GetManifestModule()->LoadModule(::GetAppDomain(), mdLinkRef, FALSE, loadFlag!=Loader::Load);
947
948 if (pDomainModule == NULL)
949 RETURN NULL;
950 else
951 {
952 pModule = pDomainModule->GetCurrentModule();
953 if (pModule == NULL)
954 {
955 _ASSERTE(loadFlag!=Loader::Load);
956 }
957
958 RETURN pModule;
959 }
960#endif // DACCESS_COMPILE
961 }
962
963 case mdtExportedType:
964 // Only override the nested type token if it hasn't been set yet.
965 if (mdNested != mdTypeDefNil)
966 mdBinding = mdNested;
967
968 RETURN FindModuleByExportedType(mdLinkRef, loadFlag, mdBinding, pCL);
969
970 default:
971 ThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN_TYPE);
972 }
973} // Assembly::FindModuleByExportedType
974
975
976// The returned Module is non-NULL unless you prevented the load by setting loadFlag=Loader::DontLoad.
977/* static */
978Module * Assembly::FindModuleByTypeRef(
979 Module * pModule,
980 mdTypeRef tkType,
981 Loader::LoadFlag loadFlag,
982 BOOL * pfNoResolutionScope)
983{
984 CONTRACT(Module *)
985 {
986 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
987 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
988 if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM();); }
989
990 MODE_ANY;
991
992 PRECONDITION(CheckPointer(pModule));
993 PRECONDITION(TypeFromToken(tkType) == mdtTypeRef);
994 PRECONDITION(CheckPointer(pfNoResolutionScope));
995 POSTCONDITION( CheckPointer(RETVAL, loadFlag==Loader::Load ? NULL_NOT_OK : NULL_OK) );
996 SUPPORTS_DAC;
997 }
998 CONTRACT_END
999
1000 // WARNING! Correctness of the type forwarder detection algorithm in code:ClassLoader::ResolveTokenToTypeDefThrowing
1001 // relies on this function not performing any form of type forwarding itself.
1002
1003 IMDInternalImport * pImport;
1004 mdTypeRef tkTopLevelEncloserTypeRef;
1005
1006 pImport = pModule->GetMDImport();
1007 if (TypeFromToken(tkType) != mdtTypeRef)
1008 {
1009 ThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN_TYPE);
1010 }
1011
1012 {
1013 // Find the top level encloser
1014 GCX_NOTRIGGER();
1015
1016 // If nested, get top level encloser's impl
1017 int iter = 0;
1018 int maxIter = 1000;
1019 do
1020 {
1021 _ASSERTE(TypeFromToken(tkType) == mdtTypeRef);
1022 tkTopLevelEncloserTypeRef = tkType;
1023
1024 if (!pImport->IsValidToken(tkType) || iter >= maxIter)
1025 {
1026 break;
1027 }
1028
1029 IfFailThrow(pImport->GetResolutionScopeOfTypeRef(tkType, &tkType));
1030
1031 // nil-scope TR okay if there's an ExportedType
1032 // Return manifest file
1033 if (IsNilToken(tkType))
1034 {
1035 *pfNoResolutionScope = TRUE;
1036 RETURN(pModule);
1037 }
1038 iter++;
1039 }
1040 while (TypeFromToken(tkType) == mdtTypeRef);
1041 }
1042
1043 *pfNoResolutionScope = FALSE;
1044
1045#ifndef DACCESS_COMPILE
1046 if (!pImport->IsValidToken(tkType)) // redundant check only when invalid token already found.
1047 {
1048 THROW_BAD_FORMAT(BFA_BAD_TYPEREF_TOKEN, pModule);
1049 }
1050#endif //!DACCESS_COMPILE
1051
1052 switch (TypeFromToken(tkType))
1053 {
1054 case mdtModule:
1055 {
1056 // Type is in the referencing module.
1057 GCX_NOTRIGGER();
1058 CANNOTTHROWCOMPLUSEXCEPTION();
1059 RETURN( pModule );
1060 }
1061
1062 case mdtModuleRef:
1063 {
1064 if ((loadFlag != Loader::Load) || IsGCThread() || IsStackWalkerThread())
1065 {
1066 // Either we're not supposed to load, or we're doing a GC or stackwalk
1067 // in which case we shouldn't need to load. So just look up the module
1068 // and return what we find.
1069 RETURN(pModule->LookupModule(tkType,FALSE));
1070 }
1071
1072#ifndef DACCESS_COMPILE
1073 DomainFile * pActualDomainFile = pModule->LoadModule(::GetAppDomain(), tkType, FALSE, loadFlag!=Loader::Load);
1074 if (pActualDomainFile == NULL)
1075 {
1076 RETURN NULL;
1077 }
1078 else
1079 {
1080 RETURN(pActualDomainFile->GetModule());
1081 }
1082
1083#else //DACCESS_COMPILE
1084 _ASSERTE(loadFlag!=Loader::Load);
1085 DacNotImpl();
1086 RETURN NULL;
1087#endif //DACCESS_COMPILE
1088 }
1089 break;
1090
1091 case mdtAssemblyRef:
1092 {
1093 // Do this first because it has a strong contract
1094 Assembly * pAssembly = NULL;
1095
1096#if defined(FEATURE_COMINTEROP) || !defined(DACCESS_COMPILE)
1097 LPCUTF8 szNamespace = NULL;
1098 LPCUTF8 szClassName = NULL;
1099#endif
1100
1101#ifdef FEATURE_COMINTEROP
1102 if (pModule->HasBindableIdentity(tkType))
1103#endif// FEATURE_COMINTEROP
1104 {
1105 if (loadFlag == Loader::SafeLookup)
1106 {
1107 pAssembly = pModule->LookupAssemblyRef(tkType);
1108 }
1109 else
1110 {
1111 pAssembly = pModule->GetAssemblyIfLoaded(tkType);
1112 }
1113 }
1114#ifdef FEATURE_COMINTEROP
1115 else
1116 {
1117 _ASSERTE(IsAfContentType_WindowsRuntime(pModule->GetAssemblyRefFlags(tkType)));
1118
1119 if (FAILED(pImport->GetNameOfTypeRef(
1120 tkTopLevelEncloserTypeRef,
1121 &szNamespace,
1122 &szClassName)))
1123 {
1124 THROW_BAD_FORMAT(BFA_BAD_TYPEREF_TOKEN, pModule);
1125 }
1126
1127 pAssembly = pModule->GetAssemblyIfLoaded(
1128 tkType,
1129 szNamespace,
1130 szClassName,
1131 NULL); // pMDImportOverride
1132 }
1133#endif // FEATURE_COMINTEROP
1134
1135 if (pAssembly != NULL)
1136 {
1137 RETURN pAssembly->m_pManifest;
1138 }
1139
1140#ifdef DACCESS_COMPILE
1141 RETURN NULL;
1142#else
1143 if (loadFlag != Loader::Load)
1144 {
1145 RETURN NULL;
1146 }
1147
1148
1149 DomainAssembly * pDomainAssembly = pModule->LoadAssembly(
1150 ::GetAppDomain(),
1151 tkType,
1152 szNamespace,
1153 szClassName);
1154
1155
1156 if (pDomainAssembly == NULL)
1157 RETURN NULL;
1158
1159 pAssembly = pDomainAssembly->GetCurrentAssembly();
1160 if (pAssembly == NULL)
1161 {
1162 RETURN NULL;
1163 }
1164 else
1165 {
1166 RETURN pAssembly->m_pManifest;
1167 }
1168#endif //!DACCESS_COMPILE
1169 }
1170
1171 default:
1172 ThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN_TYPE);
1173 }
1174} // Assembly::FindModuleByTypeRef
1175
1176#ifndef DACCESS_COMPILE
1177
1178Module *Assembly::FindModuleByName(LPCSTR pszModuleName)
1179{
1180 CONTRACT(Module *)
1181 {
1182 THROWS;
1183 GC_TRIGGERS;
1184 INJECT_FAULT(COMPlusThrowOM(););
1185 MODE_ANY;
1186 POSTCONDITION(CheckPointer(RETVAL));
1187 }
1188 CONTRACT_END;
1189
1190 CQuickBytes qbLC;
1191
1192 // Need to perform case insensitive hashing.
1193 UTF8_TO_LOWER_CASE(pszModuleName, qbLC);
1194 pszModuleName = (LPUTF8) qbLC.Ptr();
1195
1196 mdFile kFile = GetManifestFileToken(pszModuleName);
1197 if (kFile == mdTokenNil)
1198 ThrowHR(COR_E_UNAUTHORIZEDACCESS);
1199
1200 if (this == SystemDomain::SystemAssembly())
1201 RETURN m_pManifest->GetModuleIfLoaded(kFile, TRUE, TRUE);
1202 else
1203 RETURN m_pManifest->LoadModule(::GetAppDomain(), kFile)->GetModule();
1204}
1205
1206void Assembly::CacheManifestExportedTypes(AllocMemTracker *pamTracker)
1207{
1208 CONTRACT_VOID
1209 {
1210 THROWS;
1211 GC_TRIGGERS;
1212 INJECT_FAULT(COMPlusThrowOM(););
1213 }
1214 CONTRACT_END;
1215
1216 // Prejitted assemblies are expected to have their table prebuilt.
1217 // If not, we do it here at load time (as if we would jit the assembly).
1218
1219 if (m_pManifest->IsPersistedObject(m_pManifest->m_pAvailableClasses))
1220 RETURN;
1221
1222 mdToken mdExportedType;
1223
1224 HENUMInternalHolder phEnum(GetManifestImport());
1225 phEnum.EnumInit(mdtExportedType,
1226 mdTokenNil);
1227
1228 ClassLoader::AvailableClasses_LockHolder lh(m_pClassLoader);
1229
1230 for(int i = 0; GetManifestImport()->EnumNext(&phEnum, &mdExportedType); i++)
1231 m_pClassLoader->AddExportedTypeHaveLock(GetManifestModule(),
1232 mdExportedType,
1233 pamTracker);
1234
1235 RETURN;
1236}
1237void Assembly::CacheManifestFiles()
1238{
1239}
1240
1241
1242//<TODO>@TODO: if module is not signed it needs to acquire the
1243//permissions from the assembly.</TODO>
1244void Assembly::PrepareModuleForAssembly(Module* module, AllocMemTracker *pamTracker)
1245{
1246 CONTRACTL
1247 {
1248 THROWS;
1249 GC_TRIGGERS;
1250 INJECT_FAULT(COMPlusThrowOM(););
1251 PRECONDITION(CheckPointer(module));
1252 }
1253 CONTRACTL_END;
1254
1255 if (module->m_pAvailableClasses != NULL && !module->IsPersistedObject(module->m_pAvailableClasses))
1256 {
1257 // ! We intentionally do not take the AvailableClass lock here. It creates problems at
1258 // startup and we haven't yet published the module yet so nobody should be searching it.
1259 m_pClassLoader->PopulateAvailableClassHashTable(module, pamTracker);
1260 }
1261
1262
1263#ifdef DEBUGGING_SUPPORTED
1264 // Modules take the DebuggerAssemblyControlFlags down from its
1265 // parent Assembly initially.
1266 module->SetDebuggerInfoBits(GetDebuggerInfoBits());
1267
1268 LOG((LF_CORDB, LL_INFO10, "Module %s: bits=0x%x\n",
1269 module->GetFile()->GetSimpleName(),
1270 module->GetDebuggerInfoBits()));
1271#endif // DEBUGGING_SUPPORTED
1272
1273 m_pManifest->EnsureFileCanBeStored(module->GetModuleRef());
1274}
1275
1276// This is the final step of publishing a Module into an Assembly. This step cannot fail.
1277void Assembly::PublishModuleIntoAssembly(Module *module)
1278{
1279 CONTRACTL
1280 {
1281 NOTHROW;
1282 GC_TRIGGERS;
1283 FORBID_FAULT;
1284 }
1285 CONTRACTL_END
1286
1287 GetManifestModule()->EnsuredStoreFile(module->GetModuleRef(), module);
1288 FastInterlockIncrement((LONG*)&m_pClassLoader->m_cUnhashedModules);
1289}
1290
1291
1292
1293
1294
1295//*****************************************************************************
1296// Set up the list of names of any friend assemblies
1297void Assembly::CacheFriendAssemblyInfo()
1298{
1299 CONTRACTL
1300 {
1301 THROWS;
1302 GC_TRIGGERS;
1303 INJECT_FAULT(COMPlusThrowOM(););
1304 }
1305 CONTRACTL_END
1306
1307 if (m_pFriendAssemblyDescriptor == NULL)
1308 {
1309 FriendAssemblyDescriptor *pFriendAssemblies = FriendAssemblyDescriptor::CreateFriendAssemblyDescriptor(this->GetManifestFile());
1310 if (pFriendAssemblies == NULL)
1311 {
1312 pFriendAssemblies = NO_FRIEND_ASSEMBLIES_MARKER;
1313 }
1314
1315 void *pvPreviousDescriptor = InterlockedCompareExchangeT(&m_pFriendAssemblyDescriptor,
1316 pFriendAssemblies,
1317 NULL);
1318
1319 if (pvPreviousDescriptor != NULL && pFriendAssemblies != NO_FRIEND_ASSEMBLIES_MARKER)
1320 {
1321 if (pFriendAssemblies != NO_FRIEND_ASSEMBLIES_MARKER)
1322 {
1323 delete pFriendAssemblies;
1324 }
1325 }
1326 }
1327} // void Assembly::CacheFriendAssemblyInfo()
1328
1329//*****************************************************************************
1330// Is the given assembly a friend of this assembly?
1331bool Assembly::GrantsFriendAccessTo(Assembly *pAccessingAssembly, FieldDesc *pFD)
1332{
1333 WRAPPER_NO_CONTRACT;
1334
1335 CacheFriendAssemblyInfo();
1336
1337 if (m_pFriendAssemblyDescriptor == NO_FRIEND_ASSEMBLIES_MARKER)
1338 {
1339 return false;
1340 }
1341
1342 return m_pFriendAssemblyDescriptor->GrantsFriendAccessTo(pAccessingAssembly, pFD);
1343}
1344
1345bool Assembly::GrantsFriendAccessTo(Assembly *pAccessingAssembly, MethodDesc *pMD)
1346{
1347 WRAPPER_NO_CONTRACT;
1348
1349 CacheFriendAssemblyInfo();
1350
1351 if (m_pFriendAssemblyDescriptor == NO_FRIEND_ASSEMBLIES_MARKER)
1352 {
1353 return false;
1354 }
1355
1356 return m_pFriendAssemblyDescriptor->GrantsFriendAccessTo(pAccessingAssembly, pMD);
1357}
1358
1359bool Assembly::GrantsFriendAccessTo(Assembly *pAccessingAssembly, MethodTable *pMT)
1360{
1361 WRAPPER_NO_CONTRACT;
1362
1363 CacheFriendAssemblyInfo();
1364
1365 if (m_pFriendAssemblyDescriptor == NO_FRIEND_ASSEMBLIES_MARKER)
1366 {
1367 return false;
1368 }
1369
1370 return m_pFriendAssemblyDescriptor->GrantsFriendAccessTo(pAccessingAssembly, pMT);
1371}
1372
1373bool Assembly::IgnoresAccessChecksTo(Assembly *pAccessedAssembly)
1374{
1375 CONTRACTL
1376 {
1377 THROWS;
1378 GC_TRIGGERS;
1379 PRECONDITION(CheckPointer(pAccessedAssembly));
1380 }
1381 CONTRACTL_END;
1382
1383 CacheFriendAssemblyInfo();
1384
1385 if (m_pFriendAssemblyDescriptor == NO_FRIEND_ASSEMBLIES_MARKER)
1386 {
1387 return false;
1388 }
1389
1390 if (pAccessedAssembly->IsDisabledPrivateReflection())
1391 {
1392 return false;
1393 }
1394
1395 return m_pFriendAssemblyDescriptor->IgnoresAccessChecksTo(pAccessedAssembly);
1396}
1397
1398
1399#ifndef CROSSGEN_COMPILE
1400
1401enum CorEntryPointType
1402{
1403 EntryManagedMain, // void main(String[])
1404 EntryCrtMain // unsigned main(void)
1405};
1406
1407void DECLSPEC_NORETURN ThrowMainMethodException(MethodDesc* pMD, UINT resID)
1408{
1409 CONTRACTL
1410 {
1411 THROWS;
1412 GC_TRIGGERS;
1413 MODE_ANY;
1414 INJECT_FAULT(COMPlusThrowOM());
1415 }
1416 CONTRACTL_END;
1417
1418 DefineFullyQualifiedNameForClassW();
1419 LPCWSTR szClassName = GetFullyQualifiedNameForClassW(pMD->GetMethodTable());
1420 LPCUTF8 szUTFMethodName;
1421 if (FAILED(pMD->GetMDImport()->GetNameOfMethodDef(pMD->GetMemberDef(), &szUTFMethodName)))
1422 {
1423 szUTFMethodName = "Invalid MethodDef record";
1424 }
1425 PREFIX_ASSUME(szUTFMethodName!=NULL);
1426 MAKE_WIDEPTR_FROMUTF8(szMethodName, szUTFMethodName);
1427 COMPlusThrowHR(COR_E_METHODACCESS, resID, szClassName, szMethodName);
1428}
1429
1430// Returns true if this is a valid main method?
1431void ValidateMainMethod(MethodDesc * pFD, CorEntryPointType *pType)
1432{
1433 CONTRACTL
1434 {
1435 THROWS;
1436 GC_TRIGGERS;
1437 MODE_ANY;
1438 INJECT_FAULT(COMPlusThrowOM());
1439
1440 PRECONDITION(CheckPointer(pType));
1441 }
1442 CONTRACTL_END;
1443
1444 // Must be static, but we don't care about accessibility
1445 if ((pFD->GetAttrs() & mdStatic) == 0)
1446 ThrowMainMethodException(pFD, IDS_EE_MAIN_METHOD_MUST_BE_STATIC);
1447
1448 if (pFD->GetNumGenericClassArgs() != 0 || pFD->GetNumGenericMethodArgs() != 0)
1449 ThrowMainMethodException(pFD, IDS_EE_LOAD_BAD_MAIN_SIG);
1450
1451 // Check for types
1452 SigPointer sig(pFD->GetSigPointer());
1453
1454 ULONG nCallConv;
1455 if (FAILED(sig.GetData(&nCallConv)))
1456 ThrowMainMethodException(pFD, BFA_BAD_SIGNATURE);
1457
1458 if (nCallConv != IMAGE_CEE_CS_CALLCONV_DEFAULT)
1459 ThrowMainMethodException(pFD, IDS_EE_LOAD_BAD_MAIN_SIG);
1460
1461 ULONG nParamCount;
1462 if (FAILED(sig.GetData(&nParamCount)))
1463 ThrowMainMethodException(pFD, BFA_BAD_SIGNATURE);
1464
1465
1466 CorElementType nReturnType;
1467 if (FAILED(sig.GetElemType(&nReturnType)))
1468 ThrowMainMethodException(pFD, BFA_BAD_SIGNATURE);
1469
1470 if ((nReturnType != ELEMENT_TYPE_VOID) && (nReturnType != ELEMENT_TYPE_I4) && (nReturnType != ELEMENT_TYPE_U4))
1471 ThrowMainMethodException(pFD, IDS_EE_MAIN_METHOD_HAS_INVALID_RTN);
1472
1473 if (nParamCount == 0)
1474 *pType = EntryCrtMain;
1475 else {
1476 *pType = EntryManagedMain;
1477
1478 if (nParamCount != 1)
1479 ThrowMainMethodException(pFD, IDS_EE_TO_MANY_ARGUMENTS_IN_MAIN);
1480
1481 CorElementType argType;
1482 CorElementType argType2 = ELEMENT_TYPE_END;
1483
1484 if (FAILED(sig.GetElemType(&argType)))
1485 ThrowMainMethodException(pFD, BFA_BAD_SIGNATURE);
1486
1487 if (argType == ELEMENT_TYPE_SZARRAY)
1488 if (FAILED(sig.GetElemType(&argType2)))
1489 ThrowMainMethodException(pFD, BFA_BAD_SIGNATURE);
1490
1491 if (argType != ELEMENT_TYPE_SZARRAY || argType2 != ELEMENT_TYPE_STRING)
1492 ThrowMainMethodException(pFD, IDS_EE_LOAD_BAD_MAIN_SIG);
1493 }
1494}
1495
1496/* static */
1497HRESULT RunMain(MethodDesc *pFD ,
1498 short numSkipArgs,
1499 INT32 *piRetVal,
1500 PTRARRAYREF *stringArgs /*=NULL*/)
1501{
1502 STATIC_CONTRACT_THROWS;
1503 _ASSERTE(piRetVal);
1504
1505 DWORD cCommandArgs = 0; // count of args on command line
1506 LPWSTR *wzArgs = NULL; // command line args
1507 HRESULT hr = S_OK;
1508
1509 *piRetVal = -1;
1510
1511 // The exit code for the process is communicated in one of two ways. If the
1512 // entrypoint returns an 'int' we take that. Otherwise we take a latched
1513 // process exit code. This can be modified by the app via setting
1514 // Environment's ExitCode property.
1515 //
1516 // When we're executing the default exe main in the default domain, set the latched exit code to
1517 // zero as a default. If it gets set to something else by user code then that value will be returned.
1518 //
1519 // StringArgs appears to be non-null only when the main method is explicitly invoked via the hosting api
1520 // or through creating a subsequent domain and running an exe within it. In those cases we don't
1521 // want to reset the (global) latched exit code.
1522 if (stringArgs == NULL)
1523 SetLatchedExitCode(0);
1524
1525 if (!pFD) {
1526 _ASSERTE(!"Must have a function to call!");
1527 return E_FAIL;
1528 }
1529
1530 CorEntryPointType EntryType = EntryManagedMain;
1531 ValidateMainMethod(pFD, &EntryType);
1532
1533 if ((EntryType == EntryManagedMain) &&
1534 (stringArgs == NULL)) {
1535 return E_INVALIDARG;
1536 }
1537
1538 ETWFireEvent(Main_V1);
1539
1540 struct Param
1541 {
1542 MethodDesc *pFD;
1543 short numSkipArgs;
1544 INT32 *piRetVal;
1545 PTRARRAYREF *stringArgs;
1546 CorEntryPointType EntryType;
1547 DWORD cCommandArgs;
1548 LPWSTR *wzArgs;
1549 } param;
1550 param.pFD = pFD;
1551 param.numSkipArgs = numSkipArgs;
1552 param.piRetVal = piRetVal;
1553 param.stringArgs = stringArgs;
1554 param.EntryType = EntryType;
1555 param.cCommandArgs = cCommandArgs;
1556 param.wzArgs = wzArgs;
1557
1558 EX_TRY_NOCATCH(Param *, pParam, &param)
1559 {
1560 MethodDescCallSite threadStart(pParam->pFD);
1561
1562 PTRARRAYREF StrArgArray = NULL;
1563 GCPROTECT_BEGIN(StrArgArray);
1564
1565 // Build the parameter array and invoke the method.
1566 if (pParam->EntryType == EntryManagedMain) {
1567 if (pParam->stringArgs == NULL) {
1568 // Allocate a COM Array object with enough slots for cCommandArgs - 1
1569 StrArgArray = (PTRARRAYREF) AllocateObjectArray((pParam->cCommandArgs - pParam->numSkipArgs), g_pStringClass);
1570
1571 // Create Stringrefs for each of the args
1572 for (DWORD arg = pParam->numSkipArgs; arg < pParam->cCommandArgs; arg++) {
1573 STRINGREF sref = StringObject::NewString(pParam->wzArgs[arg]);
1574 StrArgArray->SetAt(arg - pParam->numSkipArgs, (OBJECTREF) sref);
1575 }
1576 }
1577 else
1578 StrArgArray = *pParam->stringArgs;
1579 }
1580
1581 ARG_SLOT stackVar = ObjToArgSlot(StrArgArray);
1582
1583 if (pParam->pFD->IsVoid())
1584 {
1585 // Set the return value to 0 instead of returning random junk
1586 *pParam->piRetVal = 0;
1587 threadStart.Call(&stackVar);
1588 }
1589 else
1590 {
1591 *pParam->piRetVal = (INT32)threadStart.Call_RetArgSlot(&stackVar);
1592 SetLatchedExitCode(*pParam->piRetVal);
1593 }
1594
1595 GCPROTECT_END();
1596
1597 //<TODO>
1598 // When we get mainCRTStartup from the C++ then this should be able to go away.</TODO>
1599 fflush(stdout);
1600 fflush(stderr);
1601 }
1602 EX_END_NOCATCH
1603
1604 ETWFireEvent(MainEnd_V1);
1605
1606 return hr;
1607}
1608
1609static void RunMainPre()
1610{
1611 LIMITED_METHOD_CONTRACT;
1612
1613 _ASSERTE(GetThread() != 0);
1614 g_fWeControlLifetime = TRUE;
1615}
1616
1617static void RunMainPost()
1618{
1619 CONTRACTL
1620 {
1621 THROWS;
1622 GC_TRIGGERS;
1623 MODE_ANY;
1624 INJECT_FAULT(COMPlusThrowOM(););
1625 PRECONDITION(CheckPointer(GetThread()));
1626 }
1627 CONTRACTL_END
1628
1629 GCX_PREEMP();
1630 ThreadStore::s_pThreadStore->WaitForOtherThreads();
1631
1632 DWORD dwSecondsToSleep = g_pConfig->GetSleepOnExit();
1633
1634 // if dwSeconds is non-zero then we will sleep for that many seconds
1635 // before we exit this allows the vaDumpCmd to detect that our process
1636 // has gone idle and this allows us to get a vadump of our process at
1637 // this point in it's execution
1638 //
1639 if (dwSecondsToSleep != 0)
1640 {
1641 ClrSleepEx(dwSecondsToSleep * 1000, FALSE);
1642 }
1643}
1644
1645static void RunStartupHooks()
1646{
1647 CONTRACTL
1648 {
1649 THROWS;
1650 GC_TRIGGERS;
1651 MODE_COOPERATIVE;
1652 INJECT_FAULT(COMPlusThrowOM(););
1653 }
1654 CONTRACTL_END;
1655
1656 MethodDescCallSite processStartupHooks(METHOD__STARTUP_HOOK_PROVIDER__PROCESS_STARTUP_HOOKS);
1657 processStartupHooks.Call(NULL);
1658}
1659
1660INT32 Assembly::ExecuteMainMethod(PTRARRAYREF *stringArgs, BOOL waitForOtherThreads)
1661{
1662 CONTRACTL
1663 {
1664 INSTANCE_CHECK;
1665 THROWS;
1666 GC_TRIGGERS;
1667 MODE_ANY;
1668 ENTRY_POINT;
1669 INJECT_FAULT(COMPlusThrowOM());
1670 }
1671 CONTRACTL_END;
1672
1673 // reset the error code for std C
1674 errno=0;
1675
1676 HRESULT hr = S_OK;
1677 INT32 iRetVal = 0;
1678
1679 BEGIN_ENTRYPOINT_THROWS;
1680
1681 Thread *pThread = GetThread();
1682 MethodDesc *pMeth;
1683 {
1684 // This thread looks like it wandered in -- but actually we rely on it to keep the process alive.
1685 pThread->SetBackground(FALSE);
1686
1687 GCX_COOP();
1688
1689 pMeth = GetEntryPoint();
1690
1691 if (pMeth) {
1692 {
1693#ifdef FEATURE_COMINTEROP
1694 GCX_PREEMP();
1695
1696 Thread::ApartmentState state = Thread::AS_Unknown;
1697 state = SystemDomain::GetEntryPointThreadAptState(pMeth->GetMDImport(), pMeth->GetMemberDef());
1698 SystemDomain::SetThreadAptState(state);
1699#endif // FEATURE_COMINTEROP
1700 }
1701
1702 RunMainPre();
1703
1704 // Set the root assembly as the assembly that is containing the main method
1705 // The root assembly is used in the GetEntryAssembly method that on CoreCLR is used
1706 // to get the TargetFrameworkMoniker for the app
1707 AppDomain * pDomain = pThread->GetDomain();
1708 pDomain->SetRootAssembly(pMeth->GetAssembly());
1709
1710 RunStartupHooks();
1711
1712 hr = RunMain(pMeth, 1, &iRetVal, stringArgs);
1713 }
1714 }
1715
1716 //RunMainPost is supposed to be called on the main thread of an EXE,
1717 //after that thread has finished doing useful work. It contains logic
1718 //to decide when the process should get torn down. So, don't call it from
1719 // AppDomain.ExecuteAssembly()
1720 if (pMeth) {
1721 if (waitForOtherThreads)
1722 RunMainPost();
1723 }
1724 else {
1725 StackSString displayName;
1726 GetDisplayName(displayName);
1727 COMPlusThrowHR(COR_E_MISSINGMETHOD, IDS_EE_FAILED_TO_FIND_MAIN, displayName);
1728 }
1729
1730 IfFailThrow(hr);
1731
1732 END_ENTRYPOINT_THROWS;
1733 return iRetVal;
1734}
1735#endif // CROSSGEN_COMPILE
1736
1737MethodDesc* Assembly::GetEntryPoint()
1738{
1739 CONTRACT(MethodDesc*)
1740 {
1741 THROWS;
1742 INJECT_FAULT(COMPlusThrowOM(););
1743 MODE_ANY;
1744
1745 // Can return NULL if no entry point.
1746 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
1747 }
1748 CONTRACT_END;
1749
1750 if (m_pEntryPoint)
1751 RETURN m_pEntryPoint;
1752
1753 mdToken mdEntry = m_pManifestFile->GetEntryPointToken();
1754 if (IsNilToken(mdEntry))
1755 RETURN NULL;
1756
1757 Module *pModule = NULL;
1758 switch(TypeFromToken(mdEntry)) {
1759 case mdtFile:
1760 pModule = m_pManifest->LoadModule(::GetAppDomain(), mdEntry, FALSE)->GetModule();
1761
1762 mdEntry = pModule->GetEntryPointToken();
1763 if ( (TypeFromToken(mdEntry) != mdtMethodDef) ||
1764 (!pModule->GetMDImport()->IsValidToken(mdEntry)) )
1765 pModule = NULL;
1766 break;
1767
1768 case mdtMethodDef:
1769 if (m_pManifestFile->GetPersistentMDImport()->IsValidToken(mdEntry))
1770 pModule = m_pManifest;
1771 break;
1772 }
1773
1774 // May be unmanaged entrypoint
1775 if (!pModule)
1776 RETURN NULL;
1777
1778 // We need to get its properties and the class token for this MethodDef token.
1779 mdToken mdParent;
1780 if (FAILED(pModule->GetMDImport()->GetParentToken(mdEntry, &mdParent))) {
1781 StackSString displayName;
1782 GetDisplayName(displayName);
1783 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, IDS_EE_ILLEGAL_TOKEN_FOR_MAIN, displayName);
1784 }
1785
1786 // For the entrypoint, also validate if the paramList is valid or not. We do this check
1787 // by asking for the return-value (sequence 0) parameter to MDInternalRO::FindParamOfMethod.
1788 // Incase the parameter list is invalid, CLDB_E_FILE_CORRUPT will be returned
1789 // byMDInternalRO::FindParamOfMethod and we will bail out.
1790 //
1791 // If it does not exist (return value CLDB_E_RECORD_NOTFOUND) or if it is found (S_OK),
1792 // we do not bother as the values would have come upon ensuring a valid parameter record
1793 // list.
1794 mdParamDef pdParam;
1795 HRESULT hrValidParamList = pModule->GetMDImport()->FindParamOfMethod(mdEntry, 0, &pdParam);
1796 if (hrValidParamList == CLDB_E_FILE_CORRUPT)
1797 {
1798 // Throw an exception for bad_image_format (because of corrupt metadata)
1799 StackSString displayName;
1800 GetDisplayName(displayName);
1801 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, IDS_EE_ILLEGAL_TOKEN_FOR_MAIN, displayName);
1802 }
1803
1804 if (mdParent != COR_GLOBAL_PARENT_TOKEN) {
1805 GCX_COOP();
1806 // This code needs a class init frame, because without it, the
1807 // debugger will assume any code that results from searching for a
1808 // type handle (ie, loading an assembly) is the first line of a program.
1809 FrameWithCookie<DebuggerClassInitMarkFrame> __dcimf;
1810
1811 MethodTable * pInitialMT = ClassLoader::LoadTypeDefOrRefThrowing(pModule, mdParent,
1812 ClassLoader::ThrowIfNotFound,
1813 ClassLoader::FailIfUninstDefOrRef).GetMethodTable();
1814
1815 m_pEntryPoint = MemberLoader::FindMethod(pInitialMT, mdEntry);
1816
1817 __dcimf.Pop();
1818 }
1819 else
1820 {
1821 m_pEntryPoint = pModule->FindMethod(mdEntry);
1822 }
1823
1824 RETURN m_pEntryPoint;
1825}
1826
1827#ifndef CROSSGEN_COMPILE
1828OBJECTREF Assembly::GetExposedObject()
1829{
1830 CONTRACT(OBJECTREF)
1831 {
1832 GC_TRIGGERS;
1833 THROWS;
1834 INJECT_FAULT(COMPlusThrowOM(););
1835 MODE_COOPERATIVE;
1836 }
1837 CONTRACT_END;
1838
1839 RETURN GetDomainAssembly()->GetExposedAssemblyObject();
1840}
1841#endif // CROSSGEN_COMPILE
1842
1843/* static */
1844BOOL Assembly::FileNotFound(HRESULT hr)
1845{
1846 LIMITED_METHOD_CONTRACT;
1847 return IsHRESULTForExceptionKind(hr, kFileNotFoundException) ||
1848#ifdef FEATURE_COMINTEROP
1849 (hr == RO_E_METADATA_NAME_NOT_FOUND) ||
1850#endif //FEATURE_COMINTEROP
1851 (hr == CLR_E_BIND_TYPE_NOT_FOUND);
1852}
1853
1854
1855BOOL Assembly::GetResource(LPCSTR szName, DWORD *cbResource,
1856 PBYTE *pbInMemoryResource, Assembly** pAssemblyRef,
1857 LPCSTR *szFileName, DWORD *dwLocation,
1858 BOOL fSkipRaiseResolveEvent)
1859{
1860 CONTRACTL
1861 {
1862 THROWS;
1863 GC_TRIGGERS;
1864 INJECT_FAULT(COMPlusThrowOM(););
1865 }
1866 CONTRACTL_END;
1867
1868 DomainAssembly *pAssembly = NULL;
1869 BOOL result = GetDomainAssembly()->GetResource(szName, cbResource,
1870 pbInMemoryResource, &pAssembly,
1871 szFileName, dwLocation,
1872 fSkipRaiseResolveEvent);
1873 if (result && pAssemblyRef != NULL && pAssembly != NULL)
1874 *pAssemblyRef = pAssembly->GetAssembly();
1875
1876 return result;
1877}
1878
1879#ifdef FEATURE_PREJIT
1880BOOL Assembly::IsInstrumented()
1881{
1882 STATIC_CONTRACT_THROWS;
1883 STATIC_CONTRACT_GC_TRIGGERS;
1884 STATIC_CONTRACT_FAULT;
1885
1886 // This will set the value of m_isInstrumentedStatus by calling IsInstrumentedHelper()
1887 // that method performs string pattern matching using the Config value of ZapBBInstr
1888 // We cache the value returned from that method in m_isInstrumentedStatus
1889 //
1890 if (m_isInstrumentedStatus == IS_INSTRUMENTED_UNSET)
1891 {
1892 EX_TRY
1893 {
1894 FAULT_NOT_FATAL();
1895
1896 if (IsInstrumentedHelper())
1897 {
1898 m_isInstrumentedStatus = IS_INSTRUMENTED_TRUE;
1899 }
1900 else
1901 {
1902 m_isInstrumentedStatus = IS_INSTRUMENTED_FALSE;
1903 }
1904 }
1905
1906 EX_CATCH
1907 {
1908 m_isInstrumentedStatus = IS_INSTRUMENTED_FALSE;
1909 }
1910 EX_END_CATCH(RethrowTerminalExceptions);
1911 }
1912
1913 // At this point m_isInstrumentedStatus can't have the value of IS_INSTRUMENTED_UNSET
1914 _ASSERTE(m_isInstrumentedStatus != IS_INSTRUMENTED_UNSET);
1915
1916 return (m_isInstrumentedStatus == IS_INSTRUMENTED_TRUE);
1917}
1918
1919BOOL Assembly::IsInstrumentedHelper()
1920{
1921 STATIC_CONTRACT_THROWS;
1922 STATIC_CONTRACT_GC_TRIGGERS;
1923 STATIC_CONTRACT_FAULT;
1924
1925 // Dynamic Assemblies cannot be instrumented
1926 if (IsDynamic())
1927 return false;
1928
1929 // We must have a native image in order to perform IBC instrumentation
1930 if (!GetManifestFile()->HasNativeOrReadyToRunImage())
1931 return false;
1932
1933 // @Consider using the full name instead of the short form
1934 // (see GetFusionAssemblyName()->IsEqual).
1935
1936 LPCUTF8 szZapBBInstr = g_pConfig->GetZapBBInstr();
1937 LPCUTF8 szAssemblyName = GetSimpleName();
1938
1939 if (!szZapBBInstr || !szAssemblyName ||
1940 (*szZapBBInstr == '\0') || (*szAssemblyName == '\0'))
1941 return false;
1942
1943 // Convert to unicode so that we can do a case insensitive comparison
1944
1945 SString instrumentedAssemblyNamesList(SString::Utf8, szZapBBInstr);
1946 SString assemblyName(SString::Utf8, szAssemblyName);
1947
1948 const WCHAR *wszInstrumentedAssemblyNamesList = instrumentedAssemblyNamesList.GetUnicode();
1949 const WCHAR *wszAssemblyName = assemblyName.GetUnicode();
1950
1951 // wszInstrumentedAssemblyNamesList is a space separated list of assembly names.
1952 // We need to determine if wszAssemblyName is in this list.
1953 // If there is a "*" in the list, then all assemblies match.
1954
1955 const WCHAR * pCur = wszInstrumentedAssemblyNamesList;
1956
1957 do
1958 {
1959 _ASSERTE(pCur[0] != W('\0'));
1960 const WCHAR * pNextSpace = wcschr(pCur, W(' '));
1961 _ASSERTE(pNextSpace == NULL || pNextSpace[0] == W(' '));
1962
1963 if (pCur != pNextSpace)
1964 {
1965 // pCur is not pointing to a space
1966 _ASSERTE(pCur[0] != W(' '));
1967
1968 if (pCur[0] == W('*') && (pCur[1] == W(' ') || pCur[1] == W('\0')))
1969 return true;
1970
1971 if (pNextSpace == NULL)
1972 {
1973 // We have reached the last name in the list. There are no more spaces.
1974 return (SString::_wcsicmp(wszAssemblyName, pCur) == 0);
1975 }
1976 else
1977 {
1978 if (SString::_wcsnicmp(wszAssemblyName, pCur, static_cast<COUNT_T>(pNextSpace - pCur)) == 0)
1979 return true;
1980 }
1981 }
1982
1983 pCur = pNextSpace + 1;
1984 }
1985 while (pCur[0] != W('\0'));
1986
1987 return false;
1988}
1989#endif // FEATURE_PREJIT
1990
1991
1992#ifdef FEATURE_COMINTEROP
1993
1994ITypeLib * const Assembly::InvalidTypeLib = (ITypeLib *)-1;
1995
1996ITypeLib* Assembly::GetTypeLib()
1997{
1998 CONTRACTL
1999 {
2000 NOTHROW;
2001 GC_TRIGGERS;
2002 FORBID_FAULT;
2003 }
2004 CONTRACTL_END
2005
2006 ITypeLib *pTlb = m_pITypeLib;
2007 if (pTlb != nullptr && pTlb != Assembly::InvalidTypeLib)
2008 pTlb->AddRef();
2009
2010 return pTlb;
2011} // ITypeLib* Assembly::GetTypeLib()
2012
2013bool Assembly::TrySetTypeLib(_In_ ITypeLib *pNew)
2014{
2015 CONTRACTL
2016 {
2017 NOTHROW;
2018 GC_TRIGGERS;
2019 FORBID_FAULT;
2020 PRECONDITION(CheckPointer(pNew));
2021 }
2022 CONTRACTL_END
2023
2024 ITypeLib *pOld = InterlockedCompareExchangeT(&m_pITypeLib, pNew, nullptr);
2025 if (pOld != nullptr)
2026 return false;
2027
2028 if (pNew != Assembly::InvalidTypeLib)
2029 pNew->AddRef();
2030
2031 return true;
2032} // void Assembly::SetTypeLib()
2033
2034#endif // FEATURE_COMINTEROP
2035
2036//***********************************************************
2037// Add an assembly to the assemblyref list. pAssemEmitter specifies where
2038// the AssemblyRef is emitted to.
2039//***********************************************************
2040mdAssemblyRef Assembly::AddAssemblyRef(Assembly *refedAssembly, IMetaDataAssemblyEmit *pAssemEmitter, BOOL fUsePublicKeyToken)
2041{
2042 CONTRACT(mdAssemblyRef)
2043 {
2044 THROWS;
2045 GC_TRIGGERS;
2046 INJECT_FAULT(COMPlusThrowOM(););
2047 PRECONDITION(CheckPointer(refedAssembly));
2048 PRECONDITION(CheckPointer(pAssemEmitter, NULL_NOT_OK));
2049 POSTCONDITION(!IsNilToken(RETVAL));
2050 POSTCONDITION(TypeFromToken(RETVAL) == mdtAssemblyRef);
2051 }
2052 CONTRACT_END;
2053
2054 SafeComHolder<IMetaDataAssemblyEmit> emitHolder;
2055
2056 AssemblySpec spec;
2057 spec.InitializeSpec(refedAssembly->GetManifestFile());
2058
2059 if (refedAssembly->IsCollectible())
2060 {
2061 if (this->IsCollectible())
2062 this->GetLoaderAllocator()->EnsureReference(refedAssembly->GetLoaderAllocator());
2063 else
2064 COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleBoundNonCollectible"));
2065 }
2066
2067 mdAssemblyRef ar;
2068 IfFailThrow(spec.EmitToken(pAssemEmitter, &ar, fUsePublicKeyToken));
2069
2070 RETURN ar;
2071} // Assembly::AddAssemblyRef
2072
2073//***********************************************************
2074// Add a typedef to the runtime TypeDef table of this assembly
2075//***********************************************************
2076void Assembly::AddType(
2077 Module *pModule,
2078 mdTypeDef cl)
2079{
2080 CONTRACTL
2081 {
2082 THROWS;
2083 GC_TRIGGERS;
2084 INJECT_FAULT(COMPlusThrowOM(););
2085 }
2086 CONTRACTL_END
2087
2088 AllocMemTracker amTracker;
2089
2090 if (pModule->GetAssembly() != this)
2091 {
2092 // you cannot add a typedef outside of the assembly to the typedef table
2093 _ASSERTE(!"Bad usage!");
2094 }
2095 m_pClassLoader->AddAvailableClassDontHaveLock(pModule,
2096 cl,
2097 &amTracker);
2098 amTracker.SuppressRelease();
2099}
2100
2101//***********************************************************
2102// Add an ExportedType to the runtime TypeDef table of this assembly
2103//***********************************************************
2104void Assembly::AddExportedType(mdExportedType cl)
2105{
2106 CONTRACTL
2107 {
2108 THROWS;
2109 GC_TRIGGERS;
2110 INJECT_FAULT(COMPlusThrowOM(););
2111 }
2112 CONTRACTL_END
2113
2114 AllocMemTracker amTracker;
2115 m_pClassLoader->AddExportedTypeDontHaveLock(GetManifestModule(),
2116 cl,
2117 &amTracker);
2118 amTracker.SuppressRelease();
2119}
2120
2121
2122
2123
2124HRESULT STDMETHODCALLTYPE
2125GetAssembliesByName(LPCWSTR szAppBase,
2126 LPCWSTR szPrivateBin,
2127 LPCWSTR szAssemblyName,
2128 IUnknown *ppIUnk[],
2129 ULONG cMax,
2130 ULONG *pcAssemblies)
2131{
2132 CONTRACTL
2133 {
2134 NOTHROW;
2135 MODE_PREEMPTIVE;
2136 GC_TRIGGERS;
2137 INJECT_FAULT(return E_OUTOFMEMORY;);
2138 }
2139 CONTRACTL_END
2140
2141 HRESULT hr = S_OK;
2142
2143 if (g_fEEInit) {
2144 // Cannot call this during EE startup
2145 return MSEE_E_ASSEMBLYLOADINPROGRESS;
2146 }
2147
2148 if (!(szAssemblyName && ppIUnk && pcAssemblies))
2149 return E_POINTER;
2150
2151 hr = COR_E_NOTSUPPORTED;
2152
2153 return hr;
2154}// Used by the IMetadata API's to access an assemblies metadata.
2155
2156void DECLSPEC_NORETURN Assembly::ThrowTypeLoadException(LPCUTF8 pszFullName, UINT resIDWhy)
2157{
2158 WRAPPER_NO_CONTRACT;
2159 ThrowTypeLoadException(NULL, pszFullName, NULL,
2160 resIDWhy);
2161}
2162
2163void DECLSPEC_NORETURN Assembly::ThrowTypeLoadException(LPCUTF8 pszNameSpace, LPCUTF8 pszTypeName,
2164 UINT resIDWhy)
2165{
2166 WRAPPER_NO_CONTRACT;
2167 ThrowTypeLoadException(pszNameSpace, pszTypeName, NULL,
2168 resIDWhy);
2169
2170}
2171
2172void DECLSPEC_NORETURN Assembly::ThrowTypeLoadException(NameHandle *pName, UINT resIDWhy)
2173{
2174 STATIC_CONTRACT_THROWS;
2175
2176 if (pName->GetName()) {
2177 ThrowTypeLoadException(pName->GetNameSpace(),
2178 pName->GetName(),
2179 NULL,
2180 resIDWhy);
2181 }
2182 else
2183 ThrowTypeLoadException(pName->GetTypeModule()->GetMDImport(),
2184 pName->GetTypeToken(),
2185 resIDWhy);
2186
2187}
2188
2189void DECLSPEC_NORETURN Assembly::ThrowTypeLoadException(IMDInternalImport *pInternalImport,
2190 mdToken token,
2191 UINT resIDWhy)
2192{
2193 WRAPPER_NO_CONTRACT;
2194 ThrowTypeLoadException(pInternalImport, token, NULL, resIDWhy);
2195}
2196
2197void DECLSPEC_NORETURN Assembly::ThrowTypeLoadException(IMDInternalImport *pInternalImport,
2198 mdToken token,
2199 LPCUTF8 pszFieldOrMethodName,
2200 UINT resIDWhy)
2201{
2202 STATIC_CONTRACT_THROWS;
2203 char pszBuff[32];
2204 LPCUTF8 pszClassName = (LPCUTF8)pszBuff;
2205 LPCUTF8 pszNameSpace = "Invalid_Token";
2206
2207 if(pInternalImport->IsValidToken(token))
2208 {
2209 switch (TypeFromToken(token)) {
2210 case mdtTypeRef:
2211 if (FAILED(pInternalImport->GetNameOfTypeRef(token, &pszNameSpace, &pszClassName)))
2212 {
2213 pszNameSpace = pszClassName = "Invalid TypeRef record";
2214 }
2215 break;
2216 case mdtTypeDef:
2217 if (FAILED(pInternalImport->GetNameOfTypeDef(token, &pszClassName, &pszNameSpace)))
2218 {
2219 pszNameSpace = pszClassName = "Invalid TypeDef record";
2220 }
2221 break;
2222 case mdtTypeSpec:
2223
2224 // If you see this assert, you need to make sure the message for
2225 // this resID is appropriate for TypeSpecs
2226 _ASSERTE((resIDWhy == IDS_CLASSLOAD_GENERAL) ||
2227 (resIDWhy == IDS_CLASSLOAD_BADFORMAT) ||
2228 (resIDWhy == IDS_CLASSLOAD_TYPESPEC));
2229
2230 resIDWhy = IDS_CLASSLOAD_TYPESPEC;
2231 }
2232 }
2233 else
2234 sprintf_s(pszBuff, sizeof(pszBuff), "0x%8.8X", token);
2235
2236 ThrowTypeLoadException(pszNameSpace, pszClassName,
2237 pszFieldOrMethodName, resIDWhy);
2238}
2239
2240
2241
2242void DECLSPEC_NORETURN Assembly::ThrowTypeLoadException(LPCUTF8 pszNameSpace,
2243 LPCUTF8 pszTypeName,
2244 LPCUTF8 pszMethodName,
2245 UINT resIDWhy)
2246{
2247 STATIC_CONTRACT_THROWS;
2248
2249 StackSString displayName;
2250 GetDisplayName(displayName);
2251
2252 ::ThrowTypeLoadException(pszNameSpace, pszTypeName, displayName,
2253 pszMethodName, resIDWhy);
2254}
2255
2256void DECLSPEC_NORETURN Assembly::ThrowBadImageException(LPCUTF8 pszNameSpace,
2257 LPCUTF8 pszTypeName,
2258 UINT resIDWhy)
2259{
2260 STATIC_CONTRACT_THROWS;
2261
2262 StackSString displayName;
2263 GetDisplayName(displayName);
2264
2265 StackSString fullName;
2266 SString sNameSpace(SString::Utf8, pszNameSpace);
2267 SString sTypeName(SString::Utf8, pszTypeName);
2268 fullName.MakeFullNamespacePath(sNameSpace, sTypeName);
2269
2270 COMPlusThrowHR(COR_E_BADIMAGEFORMAT, resIDWhy, fullName, displayName);
2271}
2272
2273
2274#ifdef FEATURE_COMINTEROP
2275Assembly::WinMDStatus Assembly::GetWinMDStatus()
2276{
2277 LIMITED_METHOD_CONTRACT;
2278
2279 if (m_winMDStatus == WinMDStatus_Unknown)
2280 {
2281 IWinMDImport *pWinMDImport = GetManifestWinMDImport();
2282 if (pWinMDImport != NULL)
2283 {
2284 BOOL bIsWinMDExp;
2285 VERIFY(SUCCEEDED(pWinMDImport->IsScenarioWinMDExp(&bIsWinMDExp)));
2286
2287 if (bIsWinMDExp)
2288 {
2289 // this is a managed backed WinMD
2290 m_winMDStatus = WinMDStatus_IsManagedWinMD;
2291 }
2292 else
2293 {
2294 // this is a pure WinMD
2295 m_winMDStatus = WinMDStatus_IsPureWinMD;
2296 }
2297 }
2298 else
2299 {
2300 // this is not a WinMD at all
2301 m_winMDStatus = WinMDStatus_IsNotWinMD;
2302 }
2303 }
2304
2305 return m_winMDStatus;
2306}
2307
2308bool Assembly::IsWinMD()
2309{
2310 LIMITED_METHOD_CONTRACT;
2311 return GetWinMDStatus() != WinMDStatus_IsNotWinMD;
2312}
2313
2314bool Assembly::IsManagedWinMD()
2315{
2316 LIMITED_METHOD_CONTRACT;
2317 return GetWinMDStatus() == WinMDStatus_IsManagedWinMD;
2318}
2319
2320IWinMDImport *Assembly::GetManifestWinMDImport()
2321{
2322 LIMITED_METHOD_CONTRACT;
2323
2324 if (m_pManifestWinMDImport == NULL)
2325 {
2326 ReleaseHolder<IWinMDImport> pWinMDImport;
2327 if (SUCCEEDED(m_pManifest->GetMDImport()->QueryInterface(IID_IWinMDImport, (void **)&pWinMDImport)))
2328 {
2329 if (InterlockedCompareExchangeT<IWinMDImport *>(&m_pManifestWinMDImport, pWinMDImport, NULL) == NULL)
2330 {
2331 pWinMDImport.SuppressRelease();
2332 }
2333 }
2334 }
2335
2336 return m_pManifestWinMDImport;
2337}
2338
2339#endif // FEATURE_COMINTEROP
2340
2341
2342#endif // #ifndef DACCESS_COMPILE
2343
2344#ifndef DACCESS_COMPILE
2345void Assembly::EnsureActive()
2346{
2347 CONTRACTL
2348 {
2349 THROWS;
2350 GC_TRIGGERS;
2351 INJECT_FAULT(COMPlusThrowOM(););
2352 }
2353 CONTRACTL_END;
2354
2355 GetDomainAssembly()->EnsureActive();
2356}
2357#endif //!DACCESS_COMPILE
2358
2359CHECK Assembly::CheckActivated()
2360{
2361#ifndef DACCESS_COMPILE
2362 WRAPPER_NO_CONTRACT;
2363
2364 CHECK(GetDomainAssembly()->CheckActivated());
2365#endif
2366 CHECK_OK;
2367}
2368
2369
2370
2371#ifdef DACCESS_COMPILE
2372
2373void
2374Assembly::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2375{
2376 WRAPPER_NO_CONTRACT;
2377 SUPPORTS_DAC;
2378
2379 // We don't need Assembly info in triage dumps.
2380 if (flags == CLRDATA_ENUM_MEM_TRIAGE)
2381 {
2382 return;
2383 }
2384
2385 DAC_ENUM_DTHIS();
2386 EMEM_OUT(("MEM: %p Assembly\n", dac_cast<TADDR>(this)));
2387
2388 if (m_pDomain.IsValid())
2389 {
2390 m_pDomain->EnumMemoryRegions(flags, true);
2391 }
2392 if (m_pClassLoader.IsValid())
2393 {
2394 m_pClassLoader->EnumMemoryRegions(flags);
2395 }
2396 if (m_pManifest.IsValid())
2397 {
2398 m_pManifest->EnumMemoryRegions(flags, true);
2399 }
2400 if (m_pManifestFile.IsValid())
2401 {
2402 m_pManifestFile->EnumMemoryRegions(flags);
2403 }
2404}
2405
2406#endif
2407
2408#ifndef DACCESS_COMPILE
2409
2410FriendAssemblyDescriptor::FriendAssemblyDescriptor()
2411{
2412}
2413
2414FriendAssemblyDescriptor::~FriendAssemblyDescriptor()
2415{
2416 CONTRACTL
2417 {
2418 DESTRUCTOR_CHECK;
2419 }
2420 CONTRACTL_END;
2421
2422 ArrayList::Iterator itFullAccessAssemblies = m_alFullAccessFriendAssemblies.Iterate();
2423 while (itFullAccessAssemblies.Next())
2424 {
2425 FriendAssemblyName_t *pFriendAssemblyName = static_cast<FriendAssemblyName_t *>(itFullAccessAssemblies.GetElement());
2426 delete pFriendAssemblyName;
2427 }
2428}
2429
2430
2431//---------------------------------------------------------------------------------------
2432//
2433// Builds a FriendAssemblyDescriptor for a given assembly
2434//
2435// Arguments:
2436// pAssembly - assembly to get friend assembly information for
2437//
2438// Return Value:
2439// A friend assembly descriptor if the assembly declares any friend assemblies, otherwise NULL
2440//
2441
2442// static
2443FriendAssemblyDescriptor *FriendAssemblyDescriptor::CreateFriendAssemblyDescriptor(PEAssembly *pAssembly)
2444{
2445 CONTRACTL
2446 {
2447 THROWS;
2448 GC_TRIGGERS;
2449 PRECONDITION(CheckPointer(pAssembly));
2450 }
2451 CONTRACTL_END
2452
2453 NewHolder<FriendAssemblyDescriptor> pFriendAssemblies = new FriendAssemblyDescriptor;
2454
2455 // We're going to do this twice, once for InternalsVisibleTo and once for IgnoresAccessChecks
2456 ReleaseHolder<IMDInternalImport> pImport(pAssembly->GetMDImportWithRef());
2457 for(int count = 0 ; count < 2 ; ++count)
2458 {
2459 _ASSERTE(pImport != NULL);
2460 MDEnumHolder hEnum(pImport);
2461 HRESULT hr = S_OK;
2462
2463 if (count == 0)
2464 {
2465 hr = pImport->EnumCustomAttributeByNameInit(TokenFromRid(1, mdtAssembly), FRIEND_ASSEMBLY_TYPE, &hEnum);
2466 }
2467 else
2468 {
2469 hr = pImport->EnumCustomAttributeByNameInit(TokenFromRid(1, mdtAssembly), SUBJECT_ASSEMBLY_TYPE, &hEnum);
2470 }
2471
2472 IfFailThrow(hr);
2473
2474 // Nothing to do if there are no attributes
2475 if (hr == S_FALSE)
2476 {
2477 continue;
2478 }
2479
2480 // Enumerate over the declared friends
2481 mdCustomAttribute tkAttribute;
2482 while (pImport->EnumNext(&hEnum, &tkAttribute))
2483 {
2484 // Get raw custom attribute.
2485 const BYTE *pbAttr = NULL; // Custom attribute data as a BYTE*.
2486 ULONG cbAttr = 0; // Size of custom attribute data.
2487 if (FAILED(pImport->GetCustomAttributeAsBlob(tkAttribute, reinterpret_cast<const void **>(&pbAttr), &cbAttr)))
2488 {
2489 THROW_BAD_FORMAT(BFA_INVALID_TOKEN, pAssembly);
2490 }
2491
2492 CustomAttributeParser cap(pbAttr, cbAttr);
2493 if (FAILED(cap.ValidateProlog()))
2494 {
2495 THROW_BAD_FORMAT(BFA_BAD_CA_HEADER, pAssembly);
2496 }
2497
2498 // Get the name of the friend assembly.
2499 LPCUTF8 szString;
2500 ULONG cbString;
2501 if (FAILED(cap.GetNonNullString(&szString, &cbString)))
2502 {
2503 THROW_BAD_FORMAT(BFA_BAD_CA_HEADER, pAssembly);
2504 }
2505
2506 // Convert the string to Unicode.
2507 StackSString displayName(SString::Utf8, szString, cbString);
2508
2509 // Create an AssemblyNameObject from the string.
2510 FriendAssemblyNameHolder pFriendAssemblyName;
2511 StackScratchBuffer buffer;
2512 pFriendAssemblyName = new FriendAssemblyName_t;
2513 hr = pFriendAssemblyName->Init(displayName.GetUTF8(buffer));
2514
2515 if (SUCCEEDED(hr))
2516 {
2517 hr = pFriendAssemblyName->CheckFriendAssemblyName();
2518 }
2519
2520 if (FAILED(hr))
2521 {
2522 THROW_HR_ERROR_WITH_INFO(hr, pAssembly);
2523 }
2524
2525 if (count == 1)
2526 {
2527 pFriendAssemblies->AddSubjectAssembly(pFriendAssemblyName);
2528 pFriendAssemblyName.SuppressRelease();
2529 // Below checks are unnecessary for IgnoresAccessChecks
2530 continue;
2531 }
2532
2533 // CoreCLR does not have a valid scenario for strong-named assemblies requiring their dependencies
2534 // to be strong-named as well.
2535
2536 pFriendAssemblies->AddFriendAssembly(pFriendAssemblyName);
2537
2538 pFriendAssemblyName.SuppressRelease();
2539 }
2540 }
2541
2542 pFriendAssemblies.SuppressRelease();
2543 return pFriendAssemblies.Extract();
2544}
2545
2546//---------------------------------------------------------------------------------------
2547//
2548// Adds an assembly to the list of friend assemblies for this descriptor
2549//
2550// Arguments:
2551// pFriendAssembly - friend assembly to add to the list
2552// fAllInternalsVisible - true if all internals are visible to the friend, false if only specifically
2553// marked internals are visible
2554//
2555// Notes:
2556// This method takes ownership of the friend assembly name. It is not thread safe and does not check to
2557// see if an assembly has already been added to the friend assembly list.
2558//
2559
2560void FriendAssemblyDescriptor::AddFriendAssembly(FriendAssemblyName_t *pFriendAssembly)
2561{
2562 CONTRACTL
2563 {
2564 THROWS;
2565 GC_TRIGGERS;
2566 PRECONDITION(CheckPointer(pFriendAssembly));
2567 }
2568 CONTRACTL_END
2569
2570 m_alFullAccessFriendAssemblies.Append(pFriendAssembly);
2571}
2572
2573void FriendAssemblyDescriptor::AddSubjectAssembly(FriendAssemblyName_t *pFriendAssembly)
2574{
2575 CONTRACTL
2576 {
2577 THROWS;
2578 GC_TRIGGERS;
2579 PRECONDITION(CheckPointer(pFriendAssembly));
2580 }
2581 CONTRACTL_END
2582
2583 m_subjectAssemblies.Append(pFriendAssembly);
2584}
2585
2586// static
2587bool FriendAssemblyDescriptor::IsAssemblyOnList(PEAssembly *pAssembly, const ArrayList &alAssemblyNames)
2588{
2589 CONTRACTL
2590 {
2591 THROWS;
2592 GC_TRIGGERS;
2593 PRECONDITION(CheckPointer(pAssembly));
2594 }
2595 CONTRACTL_END;
2596
2597 AssemblySpec asmDef;
2598 asmDef.InitializeSpec(pAssembly);
2599
2600 ArrayList::ConstIterator itAssemblyNames = alAssemblyNames.Iterate();
2601 while (itAssemblyNames.Next())
2602 {
2603 const FriendAssemblyName_t *pFriendAssemblyName = static_cast<const FriendAssemblyName_t *>(itAssemblyNames.GetElement());
2604 HRESULT hr = AssemblySpec::RefMatchesDef(pFriendAssemblyName, &asmDef) ? S_OK : S_FALSE;
2605
2606 if (hr == S_OK)
2607 {
2608 return true;
2609 }
2610 }
2611
2612 return false;
2613}
2614
2615#endif // !DACCESS_COMPILE
2616
2617
2618