diff options
Diffstat (limited to 'src/vm/fusionbind.cpp')
-rw-r--r-- | src/vm/fusionbind.cpp | 661 |
1 files changed, 0 insertions, 661 deletions
diff --git a/src/vm/fusionbind.cpp b/src/vm/fusionbind.cpp deleted file mode 100644 index 0a337796bb..0000000000 --- a/src/vm/fusionbind.cpp +++ /dev/null @@ -1,661 +0,0 @@ -// 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: FusionBind.cpp -** -** Purpose: Implements fusion interface -** -** - - -===========================================================*/ - -#include "common.h" - -#include <stdlib.h> -#include "fusionbind.h" -#include "shimload.h" -#include "eventtrace.h" -#include "strongnameholders.h" - -HRESULT BaseAssemblySpec::ParseName() -{ - CONTRACTL - { - INSTANCE_CHECK; - GC_NOTRIGGER; - NOTHROW; - INJECT_FAULT(return E_OUTOFMEMORY;); - } - CONTRACTL_END; - - HRESULT hr = S_OK; - - if (!m_pAssemblyName) - return S_OK; - - CQuickBytes ssName; - - hr = ssName.ConvertUtf8_UnicodeNoThrow(m_pAssemblyName); - - if (SUCCEEDED(hr)) - { - NonVMComHolder<IAssemblyName> pName; - - IfFailRet(CreateAssemblyNameObject(&pName, (LPCWSTR) ssName.Ptr(), CANOF_PARSE_DISPLAY_NAME, NULL)); - - if (m_ownedFlags & NAME_OWNED) - delete [] m_pAssemblyName; - m_pAssemblyName = NULL; - - hr = Init(pName); - } - - return hr; -} - -void BaseAssemblySpec::GetFileOrDisplayName(DWORD flags, SString &result) const -{ - CONTRACTL - { - INSTANCE_CHECK; - THROWS; - INJECT_FAULT(ThrowOutOfMemory()); - PRECONDITION(CheckValue(result)); - PRECONDITION(result.IsEmpty()); - } - CONTRACTL_END; - - if (m_pAssemblyName != NULL) { - NonVMComHolder<IAssemblyName> pFusionName; - IfFailThrow(CreateFusionName(&pFusionName)); - - FusionBind::GetAssemblyNameDisplayName(pFusionName, result, flags); - } - else - result.Set(m_wszCodeBase); -} - -HRESULT AssemblySpec::LoadAssembly(IApplicationContext* pFusionContext, - FusionSink *pSink, - IAssembly** ppIAssembly, - IHostAssembly** ppIHostAssembly, - IBindResult** ppNativeFusionAssembly, - BOOL fForIntrospectionOnly, - BOOL fSuppressSecurityChecks) -{ - CONTRACTL - { - INSTANCE_CHECK; - THROWS; - MODE_PREEMPTIVE; - INJECT_FAULT(ThrowOutOfMemory()); - } - CONTRACTL_END; - - HRESULT hr = E_FAIL; - - if (!IsAfContentType_Default(m_dwFlags)) - { // Fusion can process only Default ContentType (non-WindowsRuntime) - IfFailThrow(COR_E_BADIMAGEFORMAT); - } - - NonVMComHolder<IAssembly> pIAssembly(NULL); - NonVMComHolder<IBindResult> pNativeFusionAssembly(NULL); - NonVMComHolder<IHostAssembly> pIHostAssembly(NULL); - NonVMComHolder<IAssemblyName> pSpecName; - NonVMComHolder<IAssemblyName> pCodeBaseName; - - - BOOL fFXOnly = FALSE; - DWORD size = sizeof(fFXOnly); - - hr = pFusionContext->Get(ACTAG_FX_ONLY, &fFXOnly, &size, 0); - if(FAILED(hr)) - { - /// just in case it corrupted fFXOnly - fFXOnly = FALSE; - } - - // reset hr - hr = E_FAIL; - - // Make sure we don't have malformed names - - if (m_pAssemblyName) - IfFailGo(FusionBind::VerifyBindingString(m_pAssemblyName)); - - if (m_context.szLocale) - IfFailGo(FusionBind::VerifyBindingString(m_context.szLocale)); - - // If we have assembly name info, first bind using that - if (m_pAssemblyName != NULL) { - IfFailGo(CreateFusionName(&pSpecName, FALSE)); - - if(m_fParentLoadContext == LOADCTX_TYPE_UNKNOWN) - { - BOOL bOptionallyRetargetable; - IfFailGo(IsOptionallyRetargetableAssembly(pSpecName, &bOptionallyRetargetable)); - if (bOptionallyRetargetable) - return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); // do not propagate to load, let the event handle - } - - hr = FusionBind::RemoteLoad(pFusionContext, pSink, - pSpecName, GetParentIAssembly(), NULL, - &pIAssembly, &pIHostAssembly, &pNativeFusionAssembly, fForIntrospectionOnly, fSuppressSecurityChecks); - } - - - // Now, bind using the codebase. - if (FAILED(hr) && !fFXOnly && m_wszCodeBase) { - // No resolution by code base for SQL-hosted environment, except for introspection - if((!fForIntrospectionOnly) && CorHost2::IsLoadFromBlocked()) - { - hr = FUSION_E_LOADFROM_BLOCKED; - goto ErrExit; - } - IfFailGo(CreateAssemblyNameObject(&pCodeBaseName, NULL, 0, NULL)); - - IfFailGo(pCodeBaseName->SetProperty(ASM_NAME_CODEBASE_URL, - (void*)m_wszCodeBase, - (DWORD)(wcslen(m_wszCodeBase) + 1) * sizeof(WCHAR))); - - // Note that we cannot bind a native image using a codebase, as it will - // always be in the LoadFrom context which does not support native images. - - pSink->Reset(); - hr = FusionBind::RemoteLoad(pFusionContext, pSink, - pCodeBaseName, NULL, m_wszCodeBase, - &pIAssembly, &pIHostAssembly, &pNativeFusionAssembly, fForIntrospectionOnly, fSuppressSecurityChecks); - - // If we had both name info and codebase, make sure they are consistent. - if (SUCCEEDED(hr) && m_pAssemblyName != NULL) { - - NonVMComHolder<IAssemblyName> pPolicyRefName(NULL); - if (!fForIntrospectionOnly) { - // Get post-policy ref, because we'll be comparing - // it against a post-policy def - HRESULT policyHr = PreBindAssembly(pFusionContext, - pSpecName, - NULL, // pAsmParent - &pPolicyRefName, - NULL); // pvReserved - if (FAILED(policyHr) && (policyHr != FUSION_E_REF_DEF_MISMATCH) && - (policyHr != E_INVALIDARG)) // partial ref - IfFailGo(policyHr); - } - - NonVMComHolder<IAssemblyName> pBoundName; - if (pIAssembly == NULL) - IfFailGo(pIHostAssembly->GetAssemblyNameDef(&pBoundName)); - else - IfFailGo(pIAssembly->GetAssemblyNameDef(&pBoundName)); - - // Order matters: Ref->IsEqual(Def) - HRESULT equalHr; - if (pPolicyRefName) - equalHr = pPolicyRefName->IsEqual(pBoundName, ASM_CMPF_DEFAULT); - else - equalHr = pSpecName->IsEqual(pBoundName, ASM_CMPF_DEFAULT); - if (equalHr != S_OK) - { - // post-policy name is pBoundName and it's not correct for the - // original name, so we need to clear it - ReleaseNameAfterPolicy(); - IfFailGo(FUSION_E_REF_DEF_MISMATCH); - } - } - } - - // We should have found an assembly by now. - IfFailGo(hr); - - // <NOTE> Comment about the comment below. The work is done in fusion now. - // But we still keep the comment here to illustrate the problem. </NOTE> - - // Until we can create multiple Assembly objects for a single HMODULE - // we can only store one IAssembly* per Assembly. It is very important - // to maintain the IAssembly* for an image that is in the load-context. - // An Assembly in the load-from-context can bind to an assembly in the - // load-context but not visa-versa. Therefore, if we every get an IAssembly - // from the load-from-context we must make sure that it will never be - // found using a load. If it did then we could end up with Assembly dependencies - // that are wrong. For example, if I do a LoadFrom() on an assembly in the GAC - // and it requires another Assembly that I have preloaded in the load-from-context - // then that dependency gets burnt into the Jitted code. Later on a Load() is - // done on the assembly in the GAC and we single instance it back to the one - // we have gotten from the load-from-context because the HMODULES are the same. - // Now the dependency is wrong because it would not have the preloaded assembly - // if the order was reversed. - -#if 0 - if (!fForIntrospectionOnly) - { - NonVMComHolder<IFusionLoadContext> pLoadContext; - if (pIAssembly == NULL) - IfFailGo(pIHostAssembly->GetFusionLoadContext(&pLoadContext)); - else - IfFailGo(pIAssembly->GetFusionLoadContext(&pLoadContext)); - - if (pLoadContext->GetContextType() == LOADCTX_TYPE_LOADFROM) { - _ASSERTE(pIAssembly != NULL); - HRESULT hrLocal; - - NonVMComHolder<IAssemblyName> pBoundName; - pIAssembly->GetAssemblyNameDef(&pBoundName); - - // We need to copy the bound name to modify it - IAssemblyName *pClone; - IfFailGo(pBoundName->Clone(&pClone)); - pBoundName.Release(); - pBoundName = pClone; - - // Null out the architecture for the second bind - IfFailGo(pBoundName->SetProperty(ASM_NAME_ARCHITECTURE, NULL, 0)); - - NonVMComHolder<IAssembly> pAliasingAssembly; - NonVMComHolder<IHostAssembly> pIHA; - pSink->Reset(); - hrLocal = FusionBind::RemoteLoad(pFusionContext, pSink, - pBoundName, NULL, NULL, - &pAliasingAssembly, &pIHA, fForIntrospectionOnly); - - if(SUCCEEDED(hrLocal)) { - // If the paths are the same or the loadfrom assembly is in the GAC, - // then use the non-LoadFrom assembly as the result. - - DWORD location; - hrLocal = pIAssembly->GetAssemblyLocation(&location); - BOOL alias = (SUCCEEDED(hrLocal) && location == ASMLOC_GAC); - - if (!alias) { - SString boundPath; - GetAssemblyManifestModulePath(pIAssembly, boundPath); - - SString aliasingPath; - GetAssemblyManifestModulePath(pAliasingAssembly, aliasingPath); - - alias = SString::_wcsicmp(boundPath, aliasingPath) == 0; - } - - // Keep the default context's IAssembly if the paths are the same - if (alias) - pIAssembly = pAliasingAssembly.Extract(); - } - } - } -#endif - - if (SUCCEEDED(hr)) { - if (pIAssembly == NULL) - *ppIHostAssembly = pIHostAssembly.Extract(); - else - *ppIAssembly = pIAssembly.Extract(); - if (ppNativeFusionAssembly) { - *ppNativeFusionAssembly = pNativeFusionAssembly.Extract(); - } - } - - ErrExit: - return hr; -} - - -/* static */ -HRESULT FusionBind::RemoteLoad(IApplicationContext* pFusionContext, - FusionSink *pSink, - IAssemblyName *pName, - IAssembly *pParentAssembly, - LPCWSTR pCodeBase, - IAssembly** ppIAssembly, - IHostAssembly** ppIHostAssembly, - IBindResult **ppNativeFusionAssembly, - BOOL fForIntrospectionOnly, - BOOL fSuppressSecurityChecks) -{ - CONTRACTL - { - THROWS; - MODE_PREEMPTIVE; - // The resulting IP must be held so the assembly will not be scavenged. - PRECONDITION(CheckPointer(ppIAssembly)); - PRECONDITION(CheckPointer(ppIHostAssembly)); - - PRECONDITION(CheckPointer(pName)); - INJECT_FAULT(return E_OUTOFMEMORY;); - } CONTRACTL_END; - - ETWOnStartup (FusionBinding_V1, FusionBindingEnd_V1); - - HRESULT hr; - ASM_BIND_FLAGS dwFlags = ASM_BINDF_NONE; - DWORD dwReserved = 0; - LPVOID pReserved = NULL; - - // Event Tracing for Windows is used to log data for performance and functional testing purposes. - // The events below are used to help measure the performance of the download phase of assembly binding (be it download of a remote file or accessing a local file on disk), - // as well as of lookup scenarios such as from a host store. - DWORD dwAppDomainId = ETWAppDomainIdNotAvailable; - if (ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_Context, TRACE_LEVEL_INFORMATION, CLR_PRIVATEBINDING_KEYWORD)) { - DWORD cbValue = sizeof(dwAppDomainId); - // Gather data used by ETW events later in this function. - if (pFusionContext == NULL || FAILED(pFusionContext->Get(ACTAG_APP_DOMAIN_ID, &dwAppDomainId, &cbValue, 0))) { - dwAppDomainId = ETWAppDomainIdNotAvailable; - } - } - - NonVMComHolder< IUnknown > pSinkIUnknown(NULL); - NonVMComHolder< IAssemblyNameBinder> pBinder(NULL); - *ppNativeFusionAssembly=NULL; - - if(pParentAssembly != NULL) { - // Only use a parent assembly hint when the parent assembly has a load context. - // Assemblies in anonymous context are not dicoverable by loader's binding rules, - // thus loader can't find their dependencies. - // Loader will only try to locate dependencies in default load context. - if (pParentAssembly->GetFusionLoadContext() != LOADCTX_TYPE_UNKNOWN) { - dwReserved = sizeof(IAssembly*); - pReserved = (LPVOID) pParentAssembly; - dwFlags = ASM_BINDF_PARENT_ASM_HINT; - } - } - - IfFailRet(pSink->AssemblyResetEvent()); - IfFailRet(pSink->QueryInterface(IID_IUnknown, (void**)&pSinkIUnknown)); - IUnknown *pFusionAssembly=NULL; - IUnknown *pNativeAssembly=NULL; - BOOL fCached = TRUE; - - - if (fForIntrospectionOnly) - { - dwFlags = (ASM_BIND_FLAGS)(dwFlags | ASM_BINDF_INSPECTION_ONLY); - } - - if (fSuppressSecurityChecks) - { - dwFlags = (ASM_BIND_FLAGS)(dwFlags | ASM_BINDF_SUPPRESS_SECURITY_CHECKS); - } - - IfFailRet(pName->QueryInterface(IID_IAssemblyNameBinder, (void **)&pBinder)); - { - // In SQL, this can call back into the runtime - CONTRACT_VIOLATION(ThrowsViolation); - hr = pBinder->BindToObject(IID_IAssembly, - pSinkIUnknown, - pFusionContext, - pCodeBase, - dwFlags, - pReserved, - dwReserved, - (void**) &pFusionAssembly, - (void**)&pNativeAssembly); - } - - if(hr == E_PENDING) { - // If there is an assembly IP then we were successful. - hr = pSink->Wait(); - if (SUCCEEDED(hr)) - hr = pSink->LastResult(); - if(SUCCEEDED(hr)) { - if(pSink->m_punk) { - if (pSink->m_pNIunk) - pNativeAssembly=pSink->m_pNIunk; - pFusionAssembly = pSink->m_punk; - fCached = FALSE; - } - else - hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); - } - } - - FireEtwBindingDownloadPhaseEnd(dwAppDomainId, ETWLoadContextNotAvailable, ETWFieldUnused, ETWLoaderLoadTypeNotAvailable, pCodeBase, NULL, GetClrInstanceId()); - - FireEtwBindingLookupAndProbingPhaseEnd(dwAppDomainId, ETWLoadContextNotAvailable, ETWFieldUnused, ETWLoaderLoadTypeNotAvailable, pCodeBase, NULL, GetClrInstanceId()); - - if (SUCCEEDED(hr)) { - // Keep a handle to ensure it does not disappear from the cache - // and allow access to modules associated with the assembly. - hr = pFusionAssembly->QueryInterface(IID_IAssembly, - (void**) ppIAssembly); - if (hr == E_NOINTERFACE) // IStream assembly - hr = pFusionAssembly->QueryInterface(IID_IHostAssembly, - (void**) ppIHostAssembly); - if (SUCCEEDED(hr) && pNativeAssembly) - hr=pNativeAssembly->QueryInterface(IID_IBindResult, - (void**)ppNativeFusionAssembly); - - if (fCached) - { - pFusionAssembly->Release(); - if(pNativeAssembly) - pNativeAssembly->Release(); - } - } - - return hr; -} - -/* static */ -HRESULT FusionBind::RemoteLoadModule(IApplicationContext * pFusionContext, - IAssemblyModuleImport* pModule, - FusionSink *pSink, - IAssemblyModuleImport** pResult) -{ - - CONTRACTL - { - NOTHROW; - PRECONDITION(CheckPointer(pFusionContext)); - PRECONDITION(CheckPointer(pModule)); - PRECONDITION(CheckPointer(pSink)); - PRECONDITION(CheckPointer(pResult)); - INJECT_FAULT(return E_OUTOFMEMORY;); - } CONTRACTL_END; - - ETWOnStartup (FusionBinding_V1, FusionBindingEnd_V1); - - HRESULT hr; - IfFailGo(pSink->AssemblyResetEvent()); - hr = pModule->BindToObject(pSink, - pFusionContext, - ASM_BINDF_NONE, - (void**) pResult); - if(hr == E_PENDING) { - // If there is an assembly IP then we were successful. - hr = pSink->Wait(); - if (SUCCEEDED(hr)) - hr = pSink->LastResult(); - if (SUCCEEDED(hr)) { - if(pSink->m_punk) - hr = pSink->m_punk->QueryInterface(IID_IAssemblyModuleImport, - (void**) pResult); - else - hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); - } - } - - ErrExit: - return hr; -} - - -/* static */ -HRESULT FusionBind::AddEnvironmentProperty(__in LPCWSTR variable, - __in LPCWSTR pProperty, - IApplicationContext* pFusionContext) -{ - CONTRACTL - { - NOTHROW; - PRECONDITION(CheckPointer(pProperty)); - PRECONDITION(CheckPointer(variable)); - PRECONDITION(CheckPointer(pFusionContext)); - INJECT_FAULT(return E_OUTOFMEMORY;); - } - CONTRACTL_END; - - DWORD size = _MAX_PATH; - WCHAR rcValue[_MAX_PATH]; // Buffer for the directory. - WCHAR *pValue = &(rcValue[0]); - size = WszGetEnvironmentVariable(variable, pValue, size); - if(size > _MAX_PATH) { - pValue = (WCHAR*) _alloca(size * sizeof(WCHAR)); - size = WszGetEnvironmentVariable(variable, pValue, size); - size++; // Add in the null terminator - } - - if(size) - return pFusionContext->Set(pProperty, - pValue, - size * sizeof(WCHAR), - 0); - else - return S_FALSE; // no variable found -} - -// Fusion uses a context class to drive resolution of assemblies. -// Each application has properties that can be pushed into the -// fusion context (see fusionp.h). The public api is part of -// application domains. -/* static */ -HRESULT FusionBind::SetupFusionContext(LPCWSTR szAppBase, - LPCWSTR szPrivateBin, - IApplicationContext** ppFusionContext) -{ - CONTRACTL - { - NOTHROW; - PRECONDITION(CheckPointer(ppFusionContext)); - INJECT_FAULT(return E_OUTOFMEMORY;); - } - CONTRACTL_END; - - HRESULT hr; - NonVMComHolder <IApplicationContext> pFusionContext; - - LPCWSTR pBase; - // if the appbase is null then use the current directory - if (szAppBase == NULL) { - pBase = (LPCWSTR) _alloca(_MAX_PATH * sizeof(WCHAR)); - if(!WszGetCurrentDirectory(_MAX_PATH, (LPWSTR) pBase)) - IfFailGo(HRESULT_FROM_GetLastError()); - } - else - pBase = szAppBase; - - - IfFailGo(CreateFusionContext(pBase, &pFusionContext)); - - - IfFailGo((pFusionContext)->Set(ACTAG_APP_BASE_URL, - (void*) pBase, - (DWORD)(wcslen(pBase) + 1) * sizeof(WCHAR), - 0)); - - if (szPrivateBin) - IfFailGo((pFusionContext)->Set(ACTAG_APP_PRIVATE_BINPATH, - (void*) szPrivateBin, - (DWORD)(wcslen(szPrivateBin) + 1) * sizeof(WCHAR), - 0)); - else - IfFailGo(AddEnvironmentProperty(APPENV_RELATIVEPATH, ACTAG_APP_PRIVATE_BINPATH, pFusionContext)); - - *ppFusionContext=pFusionContext; - pFusionContext.SuppressRelease(); - -ErrExit: - return hr; -} - -/* static */ -HRESULT FusionBind::CreateFusionContext(LPCWSTR pzName, IApplicationContext** ppFusionContext) -{ - CONTRACTL - { - NOTHROW; - PRECONDITION(CheckPointer(ppFusionContext)); - INJECT_FAULT(return E_OUTOFMEMORY;); - } - CONTRACTL_END; - - // This is a file name not a namespace - LPCWSTR contextName = NULL; - - if(pzName) { - contextName = wcsrchr( pzName, W('\\') ); - if(contextName) - contextName++; - else - contextName = pzName; - } - // We go off and create a fusion context for this application domain. - // Note, once it is made it can not be modified. - NonVMComHolder<IAssemblyName> pFusionAssemblyName; - HRESULT hr = CreateAssemblyNameObject(&pFusionAssemblyName, contextName, 0, NULL); - - if(SUCCEEDED(hr)) - hr = CreateApplicationContext(pFusionAssemblyName, ppFusionContext); - - return hr; -} - -/* static */ -HRESULT FusionBind::GetVersion(__out_ecount(*pdwVersion) LPWSTR pVersion, __inout DWORD* pdwVersion) -{ - CONTRACTL - { - NOTHROW; - PRECONDITION(CheckPointer(pdwVersion)); - PRECONDITION(pdwVersion>0 && CheckPointer(pVersion)); - INJECT_FAULT(return E_OUTOFMEMORY;); - } - CONTRACTL_END; - - DWORD dwCORSystem = 0; - - LPCWSTR pCORSystem = GetInternalSystemDirectory(&dwCORSystem); - - if (dwCORSystem == 0) - return E_FAIL; - - dwCORSystem--; // remove the null character - if (dwCORSystem && pCORSystem[dwCORSystem-1] == W('\\')) - dwCORSystem--; // and the trailing slash if it exists - - if (dwCORSystem==0) - return E_FAIL; - - const WCHAR* pSeparator; - const WCHAR* pTail = pCORSystem + dwCORSystem; - - for (pSeparator = pCORSystem+dwCORSystem-1; pSeparator > pCORSystem && *pSeparator != W('\\');pSeparator--); - - if (*pSeparator == W('\\')) - pSeparator++; - - DWORD lgth = (DWORD)(pTail - pSeparator); - - if (lgth > *pdwVersion) { - *pdwVersion = lgth+1; - return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); - } - -#ifdef _PREFAST_ -#pragma warning(push) -#pragma warning(disable:26000) // "Disable PREFast/espX warning about buffer overflow" -#endif - while(pSeparator < pTail) - *pVersion++ = *pSeparator++; - - *pVersion = W('\0'); -#ifdef _PREFAST_ -#pragma warning(pop) -#endif - - return S_OK; -} // FusionBind::GetVersion - |