diff options
Diffstat (limited to 'src/vm/assemblyspec.hpp')
-rw-r--r-- | src/vm/assemblyspec.hpp | 739 |
1 files changed, 739 insertions, 0 deletions
diff --git a/src/vm/assemblyspec.hpp b/src/vm/assemblyspec.hpp new file mode 100644 index 0000000000..a7e9c0f203 --- /dev/null +++ b/src/vm/assemblyspec.hpp @@ -0,0 +1,739 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/*============================================================ +** +** Header: AssemblySpec.hpp +** +** Purpose: Implements classes used to bind to assemblies +** +** + + +** +===========================================================*/ +#ifndef _ASSEMBLYSPEC_H +#define _ASSEMBLYSPEC_H +#include "hash.h" +#include "memorypool.h" +#ifdef FEATURE_FUSION +#include "fusionbind.h" +#endif +#include "assemblyspecbase.h" +#include "domainfile.h" +#include "genericstackprobe.h" +#include "holder.h" + +class AppDomain; +class Assembly; +class DomainAssembly; +enum FileLoadLevel; + +class AssemblySpec : public BaseAssemblySpec +{ + private: + + friend class AppDomain; + friend class AssemblyNameNative; + + AppDomain *m_pAppDomain; + SBuffer m_HashForControl; + DWORD m_dwHashAlg; + DomainAssembly *m_pParentAssembly; + +#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + // Contains the reference to the fallback load context associated with RefEmitted assembly requesting the load of another assembly (static or dynamic) + ICLRPrivBinder *m_pFallbackLoadContextBinder; + + // Flag to indicate if we should prefer the fallback load context binder for binding or not. + bool m_fPreferFallbackLoadContextBinder; +#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + + BOOL IsValidAssemblyName(); + + HRESULT InitializeSpecInternal(mdToken kAssemblyRefOrDef, + IMDInternalImport *pImport, + DomainAssembly *pStaticParent, + BOOL fIntrospectionOnly, + BOOL fAllowAllocation); + + // InitializeSpecInternal should be used very carefully so it's made private. + // functions that take special care (and thus are allowed to use the function) are listed below + friend Assembly * Module::GetAssemblyIfLoaded( + mdAssemblyRef kAssemblyRef, + LPCSTR szWinRtNamespace, + LPCSTR szWinRtClassName, + IMDInternalImport * pMDImportOverride, + BOOL fDoNotUtilizeExtraChecks, + ICLRPrivBinder *pBindingContextForLoadedAssembly); + + public: + +#ifndef DACCESS_COMPILE + AssemblySpec() : m_pAppDomain(::GetAppDomain()) + { + LIMITED_METHOD_CONTRACT; + m_pParentAssembly = NULL; + +#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + m_pFallbackLoadContextBinder = NULL; + m_fPreferFallbackLoadContextBinder = false; +#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + + } +#endif //!DACCESS_COMPILE + + AssemblySpec(AppDomain *pAppDomain) : m_pAppDomain(pAppDomain) + { + LIMITED_METHOD_CONTRACT + m_pParentAssembly = NULL; + +#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + m_pFallbackLoadContextBinder = NULL; + m_fPreferFallbackLoadContextBinder = false; +#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + + } + +#ifdef FEATURE_FUSION + virtual IAssembly* GetParentIAssembly(); + + virtual LPCVOID GetParentAssemblyPtr(); +#endif + + DomainAssembly* GetParentAssembly(); + + ICLRPrivBinder* GetBindingContextFromParentAssembly(AppDomain *pDomain); + + bool HasParentAssembly() + { WRAPPER_NO_CONTRACT; return GetParentAssembly() != NULL; } + + void InitializeSpec(mdToken kAssemblyRefOrDef, + IMDInternalImport *pImport, + DomainAssembly *pStaticParent = NULL, + BOOL fIntrospectionOnly = FALSE) + { + CONTRACTL + { + INSTANCE_CHECK; + GC_TRIGGERS; + THROWS; + MODE_ANY; + } + CONTRACTL_END; + HRESULT hr=InitializeSpecInternal(kAssemblyRefOrDef, pImport,pStaticParent,fIntrospectionOnly,TRUE); + if(FAILED(hr)) + EEFileLoadException::Throw(this,hr); +#ifndef FEATURE_CORECLR + CloneFields(); +#endif + }; + +#ifdef FEATURE_FUSION + void InitializeSpec(IAssemblyName *pName, + DomainAssembly *pStaticParent = NULL, + BOOL fIntrospectionOnly = FALSE); +#endif // FEATURE_FUSION + + void InitializeSpec(PEAssembly *pFile); + HRESULT InitializeSpec(StackingAllocator* alloc, + ASSEMBLYNAMEREF* pName, + BOOL fParse = TRUE, + BOOL fIntrospectionOnly = FALSE); + + void AssemblyNameInit(ASSEMBLYNAMEREF* pName, PEImage* pImageInfo); //[in,out], [in] + +#ifdef FEATURE_MIXEDMODE + void InitializeSpec(HINSTANCE hMod, BOOL fIntrospectionOnly = FALSE); +#endif // FEATURE_MIXEDMODE + + void SetCodeBase(LPCWSTR szCodeBase) + { + WRAPPER_NO_CONTRACT; + BaseAssemblySpec::SetCodeBase(szCodeBase); + } + void SetCodeBase(StackingAllocator* alloc, STRINGREF *pCodeBase); + + void SetParentAssembly(DomainAssembly *pAssembly) + { + CONTRACTL + { + INSTANCE_CHECK; + GC_NOTRIGGER; + NOTHROW; + MODE_ANY; + } + CONTRACTL_END; + + m_pParentAssembly = pAssembly; +#ifdef FEATURE_FUSION + if (pAssembly) + { + _ASSERTE(GetHostBinder() == nullptr); + m_fParentLoadContext=pAssembly->GetFile()->GetLoadContext(); + } + else + m_fParentLoadContext = LOADCTX_TYPE_DEFAULT; +#endif + } + +#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + void SetFallbackLoadContextBinderForRequestingAssembly(ICLRPrivBinder *pFallbackLoadContextBinder) + { + LIMITED_METHOD_CONTRACT; + + m_pFallbackLoadContextBinder = pFallbackLoadContextBinder; + } + + ICLRPrivBinder* GetFallbackLoadContextBinderForRequestingAssembly() + { + LIMITED_METHOD_CONTRACT; + + return m_pFallbackLoadContextBinder; + } + + void SetPreferFallbackLoadContextBinder() + { + LIMITED_METHOD_CONTRACT; + + m_fPreferFallbackLoadContextBinder = true; + } + + bool GetPreferFallbackLoadContextBinder() + { + LIMITED_METHOD_CONTRACT; + + return m_fPreferFallbackLoadContextBinder; + } +#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + + // Note that this method does not clone the fields! + void CopyFrom(AssemblySpec* pSource) + { + CONTRACTL + { + INSTANCE_CHECK; + THROWS; + MODE_ANY; + } + CONTRACTL_END; + + BaseAssemblySpec::CopyFrom(pSource); + + SetIntrospectionOnly(pSource->IsIntrospectionOnly()); + SetParentAssembly(pSource->GetParentAssembly()); + +#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + // Copy the details of the fallback load context binder + SetFallbackLoadContextBinderForRequestingAssembly(pSource->GetFallbackLoadContextBinderForRequestingAssembly()); + m_fPreferFallbackLoadContextBinder = pSource->GetPreferFallbackLoadContextBinder(); +#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) + + m_HashForControl = pSource->m_HashForControl; + m_dwHashAlg = pSource->m_dwHashAlg; + } + + +#ifndef FEATURE_FUSION + HRESULT CheckFriendAssemblyName(); +#endif // FEATURE_FUSION + + + HRESULT EmitToken(IMetaDataAssemblyEmit *pEmit, + mdAssemblyRef *pToken, + BOOL fUsePublicKeyToken = TRUE, + BOOL fMustBeBindable = FALSE /*(used only by FusionBind's implementation)*/); + + // Make sure this matches in the managed Assembly.DemandPermission() + enum FilePermFlag { + FILE_PATHDISCOVERY = 0x0, + FILE_READ = 0x1, + FILE_READANDPATHDISC = 0x2, + FILE_WEBPERM = 0x3 + }; + +#ifdef FEATURE_FUSION + static void DemandFileIOPermission(LPCWSTR wszCodeBase, + BOOL fHavePath, + DWORD dwDemandFlag); + void DemandFileIOPermission(PEAssembly *pFile); +#endif + + +#ifndef FEATURE_FUSION + VOID Bind( + AppDomain* pAppDomain, + BOOL fThrowOnFileNotFound, + CoreBindResult* pBindResult, + BOOL fNgenExplicitBind = FALSE, + BOOL fExplicitBindToNativeImage = FALSE, + StackCrawlMark *pCallerStackMark = NULL ); +#ifndef FEATURE_CORECLR + static VOID BindToSystem(BINDER_SPACE::Assembly** ppAssembly); +#endif +#endif + + Assembly *LoadAssembly(FileLoadLevel targetLevel, + AssemblyLoadSecurity *pLoadSecurity = NULL, + BOOL fThrowOnFileNotFound = TRUE, + BOOL fRaisePrebindEvents = TRUE, + StackCrawlMark *pCallerStackMark = NULL); + DomainAssembly *LoadDomainAssembly(FileLoadLevel targetLevel, + AssemblyLoadSecurity *pLoadSecurity = NULL, + BOOL fThrowOnFileNotFound = TRUE, + BOOL fRaisePrebindEvents = TRUE, + StackCrawlMark *pCallerStackMark = NULL); + + //**************************************************************************************** + // + // Creates and loads an assembly based on the name and context. + static Assembly *LoadAssembly(LPCSTR pSimpleName, + AssemblyMetaDataInternal* pContext, + const BYTE * pbPublicKeyOrToken, + DWORD cbPublicKeyOrToken, + DWORD dwFlags); + +#ifdef FEATURE_FUSION + //**************************************************************************************** + // + HRESULT LoadAssembly(IApplicationContext *pFusionContext, + FusionSink *pSink, + IAssembly** ppIAssembly, + IHostAssembly** ppIHostAssembly, + IBindResult **ppNativeFusionAssembly, + BOOL fForIntrospectionOnly, + BOOL fSuppressSecurityChecks); +#endif + + // Load an assembly based on an explicit path + static Assembly *LoadAssembly(LPCWSTR pFilePath); + +#ifdef FEATURE_FUSION + BOOL FindAssemblyFile(AppDomain *pAppDomain, BOOL fThrowOnFileNotFound, + IAssembly** ppIAssembly, IHostAssembly **ppIHostAssembly, IBindResult** pNativeFusionAssembly, + IFusionBindLog **ppFusionLog, HRESULT *pHRBindResult, StackCrawlMark *pCallerStackMark = NULL, + AssemblyLoadSecurity *pLoadSecurity = NULL); +#endif // FEATURE_FUSION + + private: + void MatchRetargetedPublicKeys(Assembly *pAssembly); + public: + void MatchPublicKeys(Assembly *pAssembly); + PEAssembly *ResolveAssemblyFile(AppDomain *pAppDomain, BOOL fPreBind); + + AppDomain *GetAppDomain() + { + LIMITED_METHOD_CONTRACT; + return m_pAppDomain; + } + + HRESULT SetHashForControl(PBYTE pHashForControl, DWORD dwHashForControl, DWORD dwHashAlg) + { + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + PRECONDITION(CheckPointer(pHashForControl)); + } + CONTRACTL_END; + + m_HashForControl.Set(pHashForControl, dwHashForControl); + m_dwHashAlg=dwHashAlg; + return S_OK; + } + + void ParseEncodedName(); + + void SetWindowsRuntimeType(LPCUTF8 szNamespace, LPCUTF8 szClassName); + void SetWindowsRuntimeType(SString const & _ssTypeName); + + inline HRESULT SetContentType(AssemblyContentType type) + { + LIMITED_METHOD_CONTRACT; + if (type == AssemblyContentType_Default) + { + m_dwFlags = (m_dwFlags & ~afContentType_Mask) | afContentType_Default; + return S_OK; + } + else if (type == AssemblyContentType_WindowsRuntime) + { + m_dwFlags = (m_dwFlags & ~afContentType_Mask) | afContentType_WindowsRuntime; + return S_OK; + } + else + { + _ASSERTE(!"Unexpected content type."); + return E_UNEXPECTED; + } + } + + // Returns true if the object can be used to bind to the target assembly. + // One case in which this is not true is when the content type is WinRT + // but no type name has been set. + inline bool HasBindableIdentity() const + { + STATIC_CONTRACT_LIMITED_METHOD; +#ifdef FEATURE_COMINTEROP + return (HasUniqueIdentity() || + (IsContentType_WindowsRuntime() && (GetWinRtTypeClassName() != NULL))); +#else + return TRUE; +#endif + } + + inline BOOL CanUseWithBindingCache() const + { + STATIC_CONTRACT_LIMITED_METHOD; +#if defined(FEATURE_APPX_BINDER) + return (GetHostBinder() == nullptr) && HasUniqueIdentity(); +#else + return HasUniqueIdentity(); +#endif + } + + inline ICLRPrivBinder *GetHostBinder() const + { + LIMITED_METHOD_CONTRACT; + return m_pHostBinder; + } + + inline void SetHostBinder(ICLRPrivBinder *pHostBinder) + { + LIMITED_METHOD_CONTRACT; + m_pHostBinder = pHostBinder; + } + +}; + +#define INITIAL_ASM_SPEC_HASH_SIZE 7 +class AssemblySpecHash +{ + LoaderHeap *m_pHeap; + PtrHashMap m_map; + + public: + +#ifndef DACCESS_COMPILE + AssemblySpecHash(LoaderHeap *pHeap = NULL) + : m_pHeap(pHeap) + { + CONTRACTL + { + CONSTRUCTOR_CHECK; + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + m_map.Init(INITIAL_ASM_SPEC_HASH_SIZE, CompareSpecs, FALSE, NULL); + } + + ~AssemblySpecHash(); +#endif + +#ifndef DACCESS_COMPILE + // + // Returns TRUE if the spec was already in the table + // + + BOOL Store(AssemblySpec *pSpec, AssemblySpec **ppStoredSpec = NULL) + { + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + INJECT_FAULT(COMPlusThrowOM()); + } + CONTRACTL_END + + DWORD key = pSpec->Hash(); + + AssemblySpec *entry = (AssemblySpec *) m_map.LookupValue(key, pSpec); + + if (entry == (AssemblySpec*) INVALIDENTRY) + { + if (m_pHeap != NULL) + entry = new (m_pHeap->AllocMem(S_SIZE_T(sizeof(AssemblySpec)))) AssemblySpec; + else + entry = new AssemblySpec; + + GCX_PREEMP(); + entry->CopyFrom(pSpec); + entry->CloneFields(AssemblySpec::ALL_OWNED); + + m_map.InsertValue(key, entry); + + if (ppStoredSpec != NULL) + *ppStoredSpec = entry; + + return FALSE; + } + else + { + if (ppStoredSpec != NULL) + *ppStoredSpec = entry; + return TRUE; + } + } +#endif // DACCESS_COMPILE + + DWORD Hash(AssemblySpec *pSpec) + { + WRAPPER_NO_CONTRACT; + return pSpec->Hash(); + } + + static BOOL CompareSpecs(UPTR u1, UPTR u2); +}; + + +class AssemblySpecBindingCache +{ + friend class AssemblyBindingHolder; + struct AssemblyBinding + { + public: + ~AssemblyBinding() + { + WRAPPER_NO_CONTRACT; + + if (m_pFile != NULL) + m_pFile->Release(); + + if (m_exceptionType==EXTYPE_EE) + delete m_pException; + }; + + void OnAppDomainUnload() + { + LIMITED_METHOD_CONTRACT; + if (m_exceptionType == EXTYPE_EE) + { + m_exceptionType = EXTYPE_NONE; + delete m_pException; + m_pException = NULL; + } + }; + + inline DomainAssembly* GetAssembly(){ LIMITED_METHOD_CONTRACT; return m_pAssembly;}; + inline void SetAssembly(DomainAssembly* pAssembly){ LIMITED_METHOD_CONTRACT; m_pAssembly=pAssembly;}; + inline PEAssembly* GetFile(){ LIMITED_METHOD_CONTRACT; return m_pFile;}; + inline BOOL IsError(){ LIMITED_METHOD_CONTRACT; return (m_exceptionType!=EXTYPE_NONE);}; + + // bound to the file, but failed later + inline BOOL IsPostBindError(){ LIMITED_METHOD_CONTRACT; return IsError() && GetFile()!=NULL;}; + + inline void ThrowIfError() + { + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + + switch(m_exceptionType) + { + case EXTYPE_NONE: return; + case EXTYPE_HR: ThrowHR(m_hr); + case EXTYPE_EE: PAL_CPP_THROW(Exception *, m_pException->DomainBoundClone()); + default: _ASSERTE(!"Unexpected exception type"); + } + }; + inline void Init(AssemblySpec* pSpec, PEAssembly* pFile, DomainAssembly* pAssembly, Exception* pEx, LoaderHeap *pHeap, AllocMemTracker *pamTracker) + { + CONTRACTL + { + THROWS; + WRAPPER(GC_TRIGGERS); + MODE_ANY; + } + CONTRACTL_END; + + InitInternal(pSpec,pFile,pAssembly); + if (pHeap != NULL) + { + m_spec.CloneFieldsToLoaderHeap(AssemblySpec::ALL_OWNED,pHeap, pamTracker); + } + else + { + m_spec.CloneFields(m_spec.ALL_OWNED); + } + InitException(pEx); + + } + + inline HRESULT GetHR() + { + LIMITED_METHOD_CONTRACT; + switch(m_exceptionType) + { + case EXTYPE_NONE: return S_OK; + case EXTYPE_HR: return m_hr; + case EXTYPE_EE: return m_pException->GetHR(); + default: _ASSERTE(!"Unexpected exception type"); + } + return E_UNEXPECTED; + }; + + inline void InitException(Exception* pEx) + { + CONTRACTL + { + THROWS; + WRAPPER(GC_TRIGGERS); + MODE_ANY; + } + CONTRACTL_END; + + _ASSERTE(m_exceptionType==EXTYPE_NONE); + + if (pEx==NULL) + return; + + _ASSERTE(!pEx->IsTransient()); + + EX_TRY + { + m_pException = pEx->DomainBoundClone(); + _ASSERTE(m_pException); + m_exceptionType=EXTYPE_EE; + } + EX_CATCH + { + InitException(pEx->GetHR()); + } + EX_END_CATCH(RethrowTransientExceptions); + + }; + + inline void InitException(HRESULT hr) + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(m_exceptionType==EXTYPE_NONE); + if (FAILED(hr)) + { + m_exceptionType=EXTYPE_HR; + m_hr=hr; + } + }; + protected: + + inline void InitInternal(AssemblySpec* pSpec, PEAssembly* pFile, DomainAssembly* pAssembly ) + { + WRAPPER_NO_CONTRACT; + m_spec.CopyFrom(pSpec); + m_pFile = pFile; + if (m_pFile) + m_pFile->AddRef(); + m_pAssembly = pAssembly; + m_exceptionType=EXTYPE_NONE; + } + + AssemblySpec m_spec; + PEAssembly *m_pFile; + DomainAssembly *m_pAssembly; + enum{ + EXTYPE_NONE = 0x00000000, + EXTYPE_HR = 0x00000001, + EXTYPE_EE = 0x00000002, + }; + INT m_exceptionType; + union + { + HRESULT m_hr; + Exception* m_pException; + }; + }; + + PtrHashMap m_map; + LoaderHeap *m_pHeap; + +#if defined(FEATURE_CORECLR) + AssemblySpecBindingCache::AssemblyBinding* GetAssemblyBindingEntryForAssemblySpec(AssemblySpec* pSpec, BOOL fThrow); +#endif // defined(FEATURE_CORECLR) + + public: + + AssemblySpecBindingCache() DAC_EMPTY(); + ~AssemblySpecBindingCache() DAC_EMPTY(); + + void Init(CrstBase *pCrst, LoaderHeap *pHeap = NULL); + void Clear(); + + void OnAppDomainUnload(); + + BOOL Contains(AssemblySpec *pSpec); + + DomainAssembly *LookupAssembly(AssemblySpec *pSpec, BOOL fThrow=TRUE); + PEAssembly *LookupFile(AssemblySpec *pSpec, BOOL fThrow = TRUE); + + BOOL StoreAssembly(AssemblySpec *pSpec, DomainAssembly *pAssembly); + BOOL StoreFile(AssemblySpec *pSpec, PEAssembly *pFile); + + BOOL StoreException(AssemblySpec *pSpec, Exception* pEx); + + DWORD Hash(AssemblySpec *pSpec) + { + WRAPPER_NO_CONTRACT; + return pSpec->Hash(); + } + + static BOOL CompareSpecs(UPTR u1, UPTR u2); +}; + +#define INITIAL_DOMAIN_ASSEMBLY_CACHE_SIZE 17 +class DomainAssemblyCache +{ + struct AssemblyEntry { + AssemblySpec spec; + LPVOID pData[2]; // Can be an Assembly, PEAssembly, or an Unmanaged DLL + + DWORD Hash() + { + WRAPPER_NO_CONTRACT; + return spec.Hash(); + } + }; + + PtrHashMap m_Table; + AppDomain* m_pDomain; + +public: + + static BOOL CompareBindingSpec(UPTR spec1, UPTR spec2); + + void InitializeTable(AppDomain* pDomain, CrstBase *pCrst) + { + WRAPPER_NO_CONTRACT; + _ASSERTE(pDomain); + m_pDomain = pDomain; + + LockOwner lock = {pCrst, IsOwnerOfCrst}; + m_Table.Init(INITIAL_DOMAIN_ASSEMBLY_CACHE_SIZE, &CompareBindingSpec, true, &lock); + } + + AssemblyEntry* LookupEntry(AssemblySpec* pSpec); + + LPVOID LookupEntry(AssemblySpec* pSpec, UINT index) + { + WRAPPER_NO_CONTRACT; + _ASSERTE(index < 2); + AssemblyEntry* ptr = LookupEntry(pSpec); + if(ptr == NULL) + return NULL; + else + return ptr->pData[index]; + } + + VOID InsertEntry(AssemblySpec* pSpec, LPVOID pData1, LPVOID pData2 = NULL); + +private: + +}; + +#endif |