//***************************************************************************** // Search the cached RegMetas for a given scope. //***************************************************************************** HRESULT LOADEDMODULES::FindCachedReadOnlyEntry( LPCWSTR szName, // Name of the desired file. DWORD dwOpenFlags, // Flags the new file is opened with. RegMeta ** ppMeta) // Put found RegMeta here. { RegMeta * pRegMeta = 0; BOOL bWillBeCopyMemory; // Will the opened file be copied to memory? DWORD dwLowFileSize; // Low bytes of this file's size DWORD dwLowFileTime; // Low butes of this file's last write time HRESULT hr; ULONG ixHash = 0; IfFailGo(InitializeStatics()); { LOCKREAD(); hr = S_FALSE; // We haven't found a match yet. // Avoid confusion. *ppMeta = NULL; bWillBeCopyMemory = IsOfCopyMemory(dwOpenFlags); // The cache is locked for read, so the list will not change. // Figure out the size and timestamp of this file WIN32_FILE_ATTRIBUTE_DATA faData; if (!WszGetFileAttributesEx(szName, GetFileExInfoStandard, &faData)) return E_FAIL; dwLowFileSize = faData.nFileSizeLow; dwLowFileTime = faData.ftLastWriteTime.dwLowDateTime; // Check the hash first. ixHash = HashFileName(szName); if ((pRegMeta = m_HashedModules[ixHash]) != NULL) { _ASSERTE(pRegMeta->IsReadOnly()); // Only match if the IsOfCopyMemory() bit is the same in both. This is because // when ofCopyMemory is set, the file is not locked on disk, and may become stale // in memory. // // Also, only match if the date and size are the same if (pRegMeta->IsCopyMemory() == bWillBeCopyMemory && pRegMeta->GetLowFileTimeOfDBFile() == dwLowFileTime && pRegMeta->GetLowFileSizeOfDBFile() == dwLowFileSize) { // If the name matches... LPCWSTR pszName = pRegMeta->GetNameOfDBFile(); #ifdef FEATURE_CASE_SENSITIVE_FILESYSTEM if (wcscmp(szName, pszName) == 0) #else if (SString::_wcsicmp(szName, pszName) == 0) #endif { ULONG cRefs; // Found it. Add a reference, and return it. *ppMeta = pRegMeta; cRefs = pRegMeta->AddRef(); LOG((LF_METADATA, LL_INFO10, "Disp::OpenScope found cached RegMeta in hash: %#8x, crefs: %d\n", pRegMeta, cRefs)); return S_OK; } } } // Not found in hash; loop through each loaded modules int count = s_pLoadedModules->Count(); for (int index = 0; index < count; index++) { pRegMeta = (*s_pLoadedModules)[index]; // If the module is read-only, and the CopyMemory bit matches, and the date // and size are the same.... if (pRegMeta->IsReadOnly() && pRegMeta->IsCopyMemory() == bWillBeCopyMemory && pRegMeta->GetLowFileTimeOfDBFile() == dwLowFileTime && pRegMeta->GetLowFileSizeOfDBFile() == dwLowFileSize) { // If the name matches... LPCWSTR pszName = pRegMeta->GetNameOfDBFile(); #ifdef FEATURE_CASE_SENSITIVE_FILESYSTEM if (wcscmp(szName, pszName) == 0) #else if (SString::_wcsicmp(szName, pszName) == 0) #endif { ULONG cRefs; // Found it. Add a reference, and return it. *ppMeta = pRegMeta; cRefs = pRegMeta->AddRef(); // Update the hash. m_HashedModules[ixHash] = pRegMeta; LOG((LF_METADATA, LL_INFO10, "Disp::OpenScope found cached RegMeta by search: %#8x, crefs: %d\n", pRegMeta, cRefs)); return S_OK; } } } } ErrExit: // Didn't find it. LOG((LF_METADATA, LL_INFO10, "Disp::OpenScope did not find cached RegMeta\n")); _ASSERTE(hr != S_OK); return hr; } // LOADEDMODULES::FindCachedReadOnlyEntry
//***************************************************************************** // GetMDInternalInterface. // This function will check the metadata section and determine if it should // return an interface which implements ReadOnly or ReadWrite. //***************************************************************************** STDAPI GetMDInternalInterface( LPVOID pData, ULONG cbData, DWORD flags, // [IN] ofRead or ofWrite. REFIID riid, // [in] The interface desired. void **ppIUnk) // [out] Return interface on success. { HRESULT hr = NOERROR; MDInternalRO *pInternalRO = NULL; IMDCommon *pInternalROMDCommon = NULL; MDFileFormat format; BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(return COR_E_STACKOVERFLOW); if (ppIUnk == NULL) IfFailGo(E_INVALIDARG); // Determine the file format we're trying to read. IfFailGo( CheckFileFormat(pData, cbData, &format) ); // Found a fully-compressed, read-only format. if ( format == MDFormat_ReadOnly ) { pInternalRO = new (nothrow) MDInternalRO; IfNullGo( pInternalRO ); IfFailGo( pInternalRO->Init(const_cast<void*>(pData), cbData) ); #ifdef FEATURE_COMINTEROP IfFailGo(pInternalRO->QueryInterface(IID_IMDCommon, (void**)&pInternalROMDCommon)); IfFailGo( (flags & ofNoTransform) ? S_FALSE : CheckIfWinMDAdapterNeeded(pInternalROMDCommon)); if (hr == S_OK) { IfFailGo(CreateWinMDInternalImportRO(pInternalROMDCommon, riid, (void**)ppIUnk)); } else #endif // FEATURE_COMINTEROP { IfFailGo(pInternalRO->QueryInterface(riid, ppIUnk)); } } else { // Found a not-fully-compressed, ENC format. _ASSERTE( format == MDFormat_ReadWrite ); IfFailGo( GetInternalWithRWFormat( pData, cbData, flags, riid, ppIUnk ) ); } ErrExit: // clean up if ( pInternalRO ) pInternalRO->Release(); if ( pInternalROMDCommon ) pInternalROMDCommon->Release(); END_SO_INTOLERANT_CODE; return hr; } // GetMDInternalInterface
JsValueRef WScriptJsrt::LoadScript(JsValueRef callee, LPCSTR fileName, LPCSTR fileContent, LPCSTR scriptInjectType, bool isSourceModule) { HRESULT hr = E_FAIL; JsErrorCode errorCode = JsNoError; LPCWSTR errorMessage = _u("Internal error."); JsValueRef returnValue = JS_INVALID_REFERENCE; JsErrorCode innerErrorCode = JsNoError; JsContextRef currentContext = JS_INVALID_REFERENCE; JsRuntimeHandle runtime = JS_INVALID_RUNTIME_HANDLE; char fullPathNarrow[_MAX_PATH]; size_t len = 0; IfJsrtErrorSetGo(ChakraRTInterface::JsGetCurrentContext(¤tContext)); IfJsrtErrorSetGo(ChakraRTInterface::JsGetRuntime(currentContext, &runtime)); if (fileName) { if (_fullpath(fullPathNarrow, fileName, _MAX_PATH) == nullptr) { IfFailGo(E_FAIL); } // canonicalize that path name to lower case for the profile storage // REVIEW: This doesn't work for UTF8... len = strlen(fullPathNarrow); for (size_t i = 0; i < len; i++) { fullPathNarrow[i] = (char)tolower(fullPathNarrow[i]); } } else { // No fileName provided (WScript.LoadScript()), use dummy "script.js" strcpy_s(fullPathNarrow, "script.js"); } if (strcmp(scriptInjectType, "self") == 0) { JsContextRef calleeContext; IfJsrtErrorSetGo(ChakraRTInterface::JsGetContextOfObject(callee, &calleeContext)); IfJsrtErrorSetGo(ChakraRTInterface::JsSetCurrentContext(calleeContext)); if (isSourceModule) { errorCode = ChakraRTInterface::JsRunModuleUtf8(fileContent, GetNextSourceContext(), fullPathNarrow, &returnValue); } else { #if ENABLE_TTD errorCode = ChakraRTInterface::JsTTDRunScript(-1, fileContent, GetNextSourceContext(), fullPathNarrow, &returnValue); #else errorCode = ChakraRTInterface::JsRunScriptUtf8(fileContent, GetNextSourceContext(), fullPathNarrow, &returnValue); #endif } if (errorCode == JsNoError) { errorCode = ChakraRTInterface::JsGetGlobalObject(&returnValue); } IfJsrtErrorSetGo(ChakraRTInterface::JsSetCurrentContext(currentContext)); } else if (strcmp(scriptInjectType, "samethread") == 0) { JsValueRef newContext = JS_INVALID_REFERENCE; // Create a new context and set it as the current context IfJsrtErrorSetGo(ChakraRTInterface::JsCreateContext(runtime, &newContext)); IfJsrtErrorSetGo(ChakraRTInterface::JsSetCurrentContext(newContext)); // Initialize the host objects Initialize(); if (isSourceModule) { errorCode = ChakraRTInterface::JsRunModuleUtf8(fileContent, GetNextSourceContext(), fullPathNarrow, &returnValue); } else { #if ENABLE_TTD errorCode = ChakraRTInterface::JsTTDRunScript(-1, fileContent, GetNextSourceContext(), fullPathNarrow, &returnValue); #else errorCode = ChakraRTInterface::JsRunScriptUtf8(fileContent, GetNextSourceContext(), fullPathNarrow, &returnValue); #endif } if (errorCode == JsNoError) { errorCode = ChakraRTInterface::JsGetGlobalObject(&returnValue); } // Set the context back to the old one ChakraRTInterface::JsSetCurrentContext(currentContext); } else { errorCode = JsErrorInvalidArgument; errorMessage = _u("Unsupported argument type inject type."); } Error: JsValueRef value = returnValue; if (errorCode != JsNoError) { if (innerErrorCode != JsNoError) { // Failed to retrieve the inner error message, so set a custom error string errorMessage = ConvertErrorCodeToMessage(errorCode); } JsValueRef error = JS_INVALID_REFERENCE; JsValueRef messageProperty = JS_INVALID_REFERENCE; ERROR_MESSAGE_TO_STRING(errCode, errorMessage, messageProperty); if (errCode == JsNoError) { errCode = ChakraRTInterface::JsCreateError(messageProperty, &error); if (errCode == JsNoError) { errCode = ChakraRTInterface::JsSetException(error); } } ChakraRTInterface::JsDoubleToNumber(errorCode, &value); } _flushall(); return value; }
HRESULT AssemblySpec::LoadAssembly(Assembly** ppAssembly, OBJECTREF* pThrowable, /*= NULL*/ OBJECTREF* pExtraEvidence, /*= NULL*/ BOOL fPolicyLoad) /*= FALSE*/ { IAssembly* pIAssembly = NULL; HRESULT hr; Assembly *pAssembly = GetAppDomain()->FindCachedAssembly(this); if(pAssembly) { if ((pExtraEvidence != NULL) && (*pExtraEvidence != NULL)) IfFailGo(SECURITY_E_INCOMPATIBLE_EVIDENCE); *ppAssembly = pAssembly; return S_FALSE; } PEFile *pFile; IfFailGo(GetAppDomain()->BindAssemblySpec(this, &pFile, &pIAssembly, &pAssembly, pExtraEvidence, pThrowable)); // Loaded by AssemblyResolve event handler if (hr == S_FALSE) { //If loaded by the AssemblyResolve event, check that // the public keys are the same as in the AR. // However, if the found assembly is a dynamically // created one, security has decided to allow it. if (m_cbPublicKeyOrToken && pAssembly->m_pManifestFile) { if (!pAssembly->m_cbPublicKey) IfFailGo(FUSION_E_PRIVATE_ASM_DISALLOWED); // Ref has the full key if (m_dwFlags & afPublicKey) { if ((m_cbPublicKeyOrToken != pAssembly->m_cbPublicKey) || memcmp(m_pbPublicKeyOrToken, pAssembly->m_pbPublicKey, m_cbPublicKeyOrToken)) IfFailGo(FUSION_E_REF_DEF_MISMATCH); } // Ref has a token else if (pAssembly->m_cbRefedPublicKeyToken) { if ((m_cbPublicKeyOrToken != pAssembly->m_cbRefedPublicKeyToken) || memcmp(m_pbPublicKeyOrToken, pAssembly->m_pbRefedPublicKeyToken, m_cbPublicKeyOrToken)) IfFailGo(FUSION_E_REF_DEF_MISMATCH); } else { if (!StrongNameTokenFromPublicKey(pAssembly->m_pbPublicKey, pAssembly->m_cbPublicKey, &pAssembly->m_pbRefedPublicKeyToken, &pAssembly->m_cbRefedPublicKeyToken)) IfFailGo(StrongNameErrorInfo()); if ((m_cbPublicKeyOrToken != pAssembly->m_cbRefedPublicKeyToken) || memcmp(m_pbPublicKeyOrToken, pAssembly->m_pbRefedPublicKeyToken, m_cbPublicKeyOrToken)) IfFailGo(FUSION_E_REF_DEF_MISMATCH); } } *ppAssembly = pAssembly; return S_OK; } // 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 (pIAssembly) { IFusionLoadContext *pLoadContext; hr = pIAssembly->GetFusionLoadContext(&pLoadContext); _ASSERTE(SUCCEEDED(hr)); if (SUCCEEDED(hr)) { if (pLoadContext->GetContextType() == LOADCTX_TYPE_LOADFROM) { mdAssembly mda; if (FAILED(pFile->GetMDImport()->GetAssemblyFromScope(&mda))) { hr = COR_E_ASSEMBLYEXPECTED; goto exit; } LPCUTF8 psName; PBYTE pbPublicKey; DWORD cbPublicKey; AssemblyMetaDataInternal context; DWORD dwFlags; pFile->GetMDImport()->GetAssemblyProps(mda, (const void**) &pbPublicKey, &cbPublicKey, NULL, // hash alg &psName, &context, &dwFlags); AssemblySpec spec; if (FAILED(hr = spec.Init(psName, &context, pbPublicKey, cbPublicKey, dwFlags))) goto exit; IAssemblyName* pFoundAssemblyName; if (FAILED(hr = spec.CreateFusionName(&pFoundAssemblyName, FALSE))) goto exit; AssemblySink* pFoundSink = GetAppDomain()->GetAssemblySink(); if(!pFoundSink) { pFoundAssemblyName->Release(); hr = E_OUTOFMEMORY; goto exit; } IAssembly *pFoundIAssembly; BEGIN_ENSURE_PREEMPTIVE_GC(); hr = FusionBind::GetAssemblyFromFusion(GetAppDomain()->GetFusionContext(), pFoundSink, pFoundAssemblyName, &spec.m_CodeInfo, &pFoundIAssembly); if(SUCCEEDED(hr)) { DWORD dwFoundSize = MAX_PATH; WCHAR wszFoundPath[MAX_PATH]; // Get the path to the module containing the manifest if (SUCCEEDED(pFoundIAssembly->GetManifestModulePath(wszFoundPath, &dwFoundSize))) { // Keep the default context's IAssembly if the paths are the same if (!_wcsicmp(wszFoundPath, pFile->GetFileName())) { pIAssembly->Release(); pIAssembly = pFoundIAssembly; // Make sure the new IAssembly isn't holding its own refcount on // the file (we've just verified we're holding the same file.) // Otherwise we will leak the handle when we unload the assembly, // assuming fusion decides to cache this IAssembly pointer // somewhere internally. PEFile::ReleaseFusionMetadataImport(pFoundIAssembly); } else pFoundIAssembly->Release(); } } pFoundAssemblyName->Release(); pFoundSink->Release(); END_ENSURE_PREEMPTIVE_GC(); hr = S_OK; } exit: pLoadContext->Release(); } } // Create the assembly and delay loading the main module. Module* pModule; hr = GetAppDomain()->LoadAssembly(pFile, pIAssembly, &pModule, &pAssembly, pExtraEvidence, fPolicyLoad, pThrowable); BEGIN_ENSURE_PREEMPTIVE_GC(); if(SUCCEEDED(hr)) { *ppAssembly = pAssembly; /*HRESULT hrLoose =*/ GetAppDomain()->AddAssemblyToCache(this, pAssembly); } if(pIAssembly) pIAssembly->Release(); END_ENSURE_PREEMPTIVE_GC(); ErrExit: if (FAILED(hr) && (pThrowable!=NULL)) { BEGIN_ENSURE_COOPERATIVE_GC(); if ((pThrowable != RETURN_ON_ERROR) && (*pThrowable == NULL)) { if (m_pAssemblyName) PostFileLoadException(m_pAssemblyName, FALSE,NULL, hr, pThrowable); else { MAKE_UTF8PTR_FROMWIDE(szName, m_CodeInfo.m_pszCodeBase); PostFileLoadException(szName, TRUE,NULL, hr, pThrowable); } } END_ENSURE_COOPERATIVE_GC(); } return hr; }
HRESULT Helpers::LoadBinaryFile(LPCSTR filename, LPCSTR& contents, UINT& lengthBytes, bool printFileOpenError) { HRESULT hr = S_OK; contents = nullptr; lengthBytes = 0; size_t result; FILE * file; // // Open the file as a binary file to prevent CRT from handling encoding, line-break conversions, // etc. // if (fopen_s(&file, filename, "rb") != 0) { if (printFileOpenError) { fprintf(stderr, "Error in opening file '%s' ", filename); #ifdef _WIN32 DWORD lastError = GetLastError(); char16 wszBuff[MAX_URI_LENGTH]; wszBuff[0] = 0; if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, lastError, 0, wszBuff, _countof(wszBuff), nullptr)) { fwprintf(stderr, _u(": %s"), wszBuff); } #endif fprintf(stderr, "\n"); } return E_FAIL; } // file will not be nullptr if _wfopen_s succeeds __analysis_assume(file != nullptr); // // Determine the file length, in bytes. // fseek(file, 0, SEEK_END); lengthBytes = ftell(file); fseek(file, 0, SEEK_SET); contents = (LPCSTR)HeapAlloc(GetProcessHeap(), 0, lengthBytes); if (nullptr == contents) { fwprintf(stderr, _u("out of memory")); IfFailGo(E_OUTOFMEMORY); } // // Read the entire content as a binary block. // result = fread((void*)contents, sizeof(char), lengthBytes, file); if (result != lengthBytes) { fwprintf(stderr, _u("Read error")); IfFailGo(E_FAIL); } Error: fclose(file); if (contents && FAILED(hr)) { HeapFree(GetProcessHeap(), 0, (void*)contents); contents = nullptr; } return hr; }
//***************************************************************************** //***************************************************************************** __checkReturn HRESULT CLiteWeightStgdbRW::SaveToStorage( TiggerStorage *pStorage, MetaDataReorderingOptions reorderingOptions, CorProfileData *pProfileData) { HRESULT hr; // A result. LPCWSTR szName; // Name of the tables stream. IStream *pIStreamTbl = 0; UINT32 cb; UINT32 cbSaveSize = m_cbSaveSize; // Must call GetSaveSize to cache the streams up front. // Don't trust cached values in the delta case... if there was a previous call to get // a non-delta size, it will be incorrect. if ((m_cbSaveSize == 0) || IsENCDelta(m_MiniMd.m_OptionValue.m_UpdateMode)) { IfFailGo(GetSaveSize(cssAccurate, &cbSaveSize)); } // Save the header of the data file. IfFailGo(pStorage->WriteHeader(m_pStreamList, 0, NULL)); // If this is a minimal delta, write a stream marker if (IsENCDelta(m_MiniMd.m_OptionValue.m_UpdateMode)) { IfFailGo(pStorage->CreateStream(MINIMAL_MD_STREAM, STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pIStreamTbl)); pIStreamTbl->Release(); pIStreamTbl = 0; } if (pProfileData != NULL) { DWORD bCompressed; UINT32 cbHotSize; // Will the stream be compressed data? // Only create this additional stream if it will be non-empty IfFailGo(m_MiniMd.GetSaveSize(cssAccurate, &cbHotSize, &bCompressed, reorderingOptions, pProfileData)); if (cbHotSize > 0) { // Create a stream and save the hot tables. szName = HOT_MODEL_STREAM; IfFailGo(pStorage->CreateStream(szName, STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pIStreamTbl)); IfFailGo(m_MiniMd.SaveTablesToStream(pIStreamTbl, reorderingOptions, pProfileData)); pIStreamTbl->Release(); pIStreamTbl = 0; } } if (reorderingOptions & ReArrangeStringPool) { // Save the string pool before the tables when we do not have the string pool cache IfFailGo(SavePool(STRING_POOL_STREAM, pStorage, MDPoolStrings)); } // Create a stream and save the tables. szName = m_bSaveCompressed ? COMPRESSED_MODEL_STREAM : ENC_MODEL_STREAM; IfFailGo(pStorage->CreateStream(szName, STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &pIStreamTbl)); IfFailGo(m_MiniMd.SaveTablesToStream(pIStreamTbl, NoReordering, NULL)); pIStreamTbl->Release(); pIStreamTbl = 0; // Save the pools. if (!(reorderingOptions & ReArrangeStringPool)) { // string pool must be saved after the tables when we have the string pool cache IfFailGo(SavePool(STRING_POOL_STREAM, pStorage, MDPoolStrings)); } IfFailGo(SavePool(US_BLOB_POOL_STREAM, pStorage, MDPoolUSBlobs)); IfFailGo(SavePool(GUID_POOL_STREAM, pStorage, MDPoolGuids)); IfFailGo(SavePool(BLOB_POOL_STREAM, pStorage, MDPoolBlobs)); // Write the header to disk. OptionValue ov; IfFailGo(m_MiniMd.GetOption(&ov)); IfFailGo(pStorage->WriteFinished(m_pStreamList, (ULONG *)&cb, IsENCDelta(ov.m_UpdateMode))); _ASSERTE(cbSaveSize == cb); // Let the Storage release some memory. pStorage->ResetBackingStore(); IfFailGo(m_MiniMd.SaveDone()); ErrExit: if (pIStreamTbl != NULL) pIStreamTbl->Release(); delete m_pStreamList; m_pStreamList = 0; m_cbSaveSize = 0; return hr; } // CLiteWeightStgdbRW::SaveToStorage
//******************************************************************************* // helper to add a declarative security blob to a class or method // // Implements internal API code:IMetaDataEmitHelper::AddDeclarativeSecurityHelper. //******************************************************************************* STDMETHODIMP RegMeta::AddDeclarativeSecurityHelper( mdToken tk, // [IN] Parent token (typedef/methoddef) DWORD dwAction, // [IN] Security action (CorDeclSecurity) void const *pValue, // [IN] Permission set blob DWORD cbValue, // [IN] Byte count of permission set blob mdPermission*pmdPermission) // [OUT] Output permission token { HRESULT hr = S_OK; DeclSecurityRec *pDeclSec = NULL; RID iDeclSec; short sAction = static_cast<short>(dwAction); mdPermission tkPerm; LOG((LOGMD, "MD RegMeta::AddDeclarativeSecurityHelper(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", tk, dwAction, pValue, cbValue, pmdPermission)); LOCKWRITE(); IfFailGo(m_pStgdb->m_MiniMd.PreUpdate()); _ASSERTE(TypeFromToken(tk) == mdtTypeDef || TypeFromToken(tk) == mdtMethodDef || TypeFromToken(tk) == mdtAssembly); // Check for valid Action. if (sAction == 0 || sAction > dclMaximumValue) IfFailGo(E_INVALIDARG); if (CheckDups(MDDupPermission)) { hr = ImportHelper::FindPermission(&(m_pStgdb->m_MiniMd), tk, sAction, &tkPerm); if (SUCCEEDED(hr)) { // Set output parameter. if (pmdPermission) *pmdPermission = tkPerm; if (IsENCOn()) IfFailGo(m_pStgdb->m_MiniMd.GetDeclSecurityRecord(RidFromToken(tkPerm), &pDeclSec)); else { hr = META_S_DUPLICATE; goto ErrExit; } } else if (hr != CLDB_E_RECORD_NOTFOUND) IfFailGo(hr); } // Create a new record. if (!pDeclSec) { IfFailGo(m_pStgdb->m_MiniMd.AddDeclSecurityRecord(&pDeclSec, &iDeclSec)); tkPerm = TokenFromRid(iDeclSec, mdtPermission); // Set output parameter. if (pmdPermission) *pmdPermission = tkPerm; // Save parent and action information. IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_DeclSecurity, DeclSecurityRec::COL_Parent, pDeclSec, tk)); pDeclSec->SetAction(sAction); // Turn on the internal security flag on the parent. if (TypeFromToken(tk) == mdtTypeDef) IfFailGo(_TurnInternalFlagsOn(tk, tdHasSecurity)); else if (TypeFromToken(tk) == mdtMethodDef) IfFailGo(_TurnInternalFlagsOn(tk, mdHasSecurity)); IfFailGo(UpdateENCLog(tk)); } // Write the blob into the record. IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_DeclSecurity, DeclSecurityRec::COL_PermissionSet, pDeclSec, pValue, cbValue)); IfFailGo(UpdateENCLog(tkPerm)); ErrExit: return hr; } // RegMeta::AddDeclarativeSecurityHelper
HRESULT RunScript(const char* fileName, LPCSTR fileContents, BYTE *bcBuffer, char *fullPath) { HRESULT hr = S_OK; MessageQueue * messageQueue = new MessageQueue(); WScriptJsrt::AddMessageQueue(messageQueue); IfJsErrorFailLog(ChakraRTInterface::JsSetPromiseContinuationCallback(PromiseContinuationCallback, (void*)messageQueue)); if(strlen(fileName) >= 14 && strcmp(fileName + strlen(fileName) - 14, "ttdSentinal.js") == 0) { #if !ENABLE_TTD wprintf(_u("Sential js file is only ok when in TTDebug mode!!!\n")); return E_FAIL; #else if(!doTTDebug) { wprintf(_u("Sential js file is only ok when in TTDebug mode!!!\n")); return E_FAIL; } ChakraRTInterface::JsTTDStart(); try { JsTTDMoveMode moveMode = (JsTTDMoveMode)(JsTTDMoveMode::JsTTDMoveKthEvent | ((int64) startEventCount) << 32); int64_t snapEventTime = -1; int64_t nextEventTime = -2; while(true) { JsErrorCode error = ChakraRTInterface::JsTTDGetSnapTimeTopLevelEventMove(chRuntime, moveMode, &nextEventTime, &snapEventTime, nullptr); if(error != JsNoError) { if(error == JsErrorCategoryUsage) { wprintf(_u("Start time not in log range.\n")); } return error; } IfFailedReturn(ChakraRTInterface::JsTTDMoveToTopLevelEvent(chRuntime, moveMode, snapEventTime, nextEventTime)); JsErrorCode res = ChakraRTInterface::JsTTDReplayExecution(&moveMode, &nextEventTime); //handle any uncaught exception by immediately time-traveling to the throwing line in the debugger -- in replay just report and exit if(res == JsErrorCategoryScript) { wprintf(_u("An unhandled script exception occoured!!!\n")); ExitProcess(0); } if(nextEventTime == -1) { wprintf(_u("\nReached end of Execution -- Exiting.\n")); break; } } } catch(...) { wprintf(_u("Terminal exception in Replay -- exiting.\n")); ExitProcess(0); } #endif } else { Assert(fileContents != nullptr || bcBuffer != nullptr); JsErrorCode runScript; JsValueRef fname; IfJsErrorFailLog(ChakraRTInterface::JsCreateStringUtf8((const uint8_t*)fullPath, strlen(fullPath), &fname)); if(bcBuffer != nullptr) { runScript = ChakraRTInterface::JsRunSerialized( bcBuffer, DummyJsSerializedScriptLoadUtf8Source, reinterpret_cast<JsSourceContext>(fileContents), // Use source ptr as sourceContext fname, nullptr /*result*/); } else { JsValueRef scriptSource; IfJsErrorFailLog(ChakraRTInterface::JsCreateExternalArrayBuffer((void*)fileContents, (unsigned int)strlen(fileContents), [](void *data) { free(data); }, nullptr, &scriptSource)); #if ENABLE_TTD if(doTTRecord) { ChakraRTInterface::JsTTDStart(); } runScript = ChakraRTInterface::JsRun(scriptSource, WScriptJsrt::GetNextSourceContext(), fname, JsParseScriptAttributeNone, nullptr /*result*/); if (runScript == JsErrorCategoryUsage) { wprintf(_u("FATAL ERROR: Core was compiled without ENABLE_TTD is defined. CH is trying to use TTD interface\n")); abort(); } #else runScript = ChakraRTInterface::JsRun(scriptSource, WScriptJsrt::GetNextSourceContext(), fname, JsParseScriptAttributeNone, nullptr /*result*/); #endif } //Do a yield after the main script body executes ChakraRTInterface::JsTTDNotifyYield(); if(runScript != JsNoError) { WScriptJsrt::PrintException(fileName, runScript); } else { // Repeatedly flush the message queue until it's empty. It is necessary to loop on this // because setTimeout can add scripts to execute. do { IfFailGo(messageQueue->ProcessAll(fileName)); } while(!messageQueue->IsEmpty()); } } Error: #if ENABLE_TTD if(doTTRecord) { ChakraRTInterface::JsTTDEmitRecording(); ChakraRTInterface::JsTTDStop(); } #endif if (messageQueue != nullptr) { messageQueue->RemoveAll(); // clean up possible pinned exception object on exit to avoid potential leak bool hasException; if (ChakraRTInterface::JsHasException(&hasException) == JsNoError && hasException) { JsValueRef exception = JS_INVALID_REFERENCE; ChakraRTInterface::JsGetAndClearException(&exception); } delete messageQueue; } return hr; }
HRESULT ExecuteTest(const char* fileName) { HRESULT hr = S_OK; LPCSTR fileContents = nullptr; JsRuntimeHandle runtime = JS_INVALID_RUNTIME_HANDLE; UINT lengthBytes = 0; if(strlen(fileName) >= 14 && strcmp(fileName + strlen(fileName) - 14, "ttdSentinal.js") == 0) { #if !ENABLE_TTD wprintf(_u("Sentinel js file is only ok when in TTDebug mode!!!\n")); return E_FAIL; #else if(!doTTDebug) { wprintf(_u("Sentinel js file is only ok when in TTDebug mode!!!\n")); return E_FAIL; } jsrtAttributes = static_cast<JsRuntimeAttributes>(jsrtAttributes | JsRuntimeAttributeEnableExperimentalFeatures); IfJsErrorFailLog(ChakraRTInterface::JsTTDCreateReplayRuntime(jsrtAttributes, ttUri, ttUriByteLength, Helpers::TTInitializeForWriteLogStreamCallback, Helpers::TTCreateStreamCallback, Helpers::TTReadBytesFromStreamCallback, Helpers::TTWriteBytesToStreamCallback, Helpers::TTFlushAndCloseStreamCallback, nullptr, &runtime)); chRuntime = runtime; JsContextRef context = JS_INVALID_REFERENCE; IfJsErrorFailLog(ChakraRTInterface::JsTTDCreateContext(runtime, true, &context)); IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(context)); IfFailGo(RunScript(fileName, fileContents, nullptr, nullptr)); unsigned int rcount = 0; IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(nullptr)); ChakraRTInterface::JsRelease(context, &rcount); AssertMsg(rcount == 0, "Should only have had 1 ref from replay code and one ref from current context??"); #endif } else { LPCOLESTR contentsRaw = nullptr; char fullPath[_MAX_PATH]; size_t len = 0; hr = Helpers::LoadScriptFromFile(fileName, fileContents, &lengthBytes); contentsRaw; lengthBytes; // Unused for now. IfFailGo(hr); if (HostConfigFlags::flags.GenerateLibraryByteCodeHeaderIsEnabled) { jsrtAttributes = (JsRuntimeAttributes)(jsrtAttributes | JsRuntimeAttributeSerializeLibraryByteCode); } #if ENABLE_TTD if (doTTRecord) { //Ensure we run with experimental features (as that is what Node does right now). jsrtAttributes = static_cast<JsRuntimeAttributes>(jsrtAttributes | JsRuntimeAttributeEnableExperimentalFeatures); IfJsErrorFailLog(ChakraRTInterface::JsTTDCreateRecordRuntime(jsrtAttributes, ttUri, ttUriByteLength, snapInterval, snapHistoryLength, Helpers::TTInitializeForWriteLogStreamCallback, Helpers::TTCreateStreamCallback, Helpers::TTReadBytesFromStreamCallback, Helpers::TTWriteBytesToStreamCallback, Helpers::TTFlushAndCloseStreamCallback, nullptr, &runtime)); chRuntime = runtime; JsContextRef context = JS_INVALID_REFERENCE; IfJsErrorFailLog(ChakraRTInterface::JsTTDCreateContext(runtime, true, &context)); #if ENABLE_TTD //We need this here since this context is created in record IfJsErrorFailLog(ChakraRTInterface::JsSetObjectBeforeCollectCallback(context, nullptr, WScriptJsrt::JsContextBeforeCollectCallback)); #endif IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(context)); } else { AssertMsg(!doTTDebug, "Should be handled in the else case above!!!"); IfJsErrorFailLog(ChakraRTInterface::JsCreateRuntime(jsrtAttributes, nullptr, &runtime)); chRuntime = runtime; if (HostConfigFlags::flags.DebugLaunch) { Debugger* debugger = Debugger::GetDebugger(runtime); debugger->StartDebugging(runtime); } JsContextRef context = JS_INVALID_REFERENCE; IfJsErrorFailLog(ChakraRTInterface::JsCreateContext(runtime, &context)); //Don't need collect callback since this is always in replay IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(context)); } #else IfJsErrorFailLog(ChakraRTInterface::JsCreateRuntime(jsrtAttributes, nullptr, &runtime)); chRuntime = runtime; if (HostConfigFlags::flags.DebugLaunch) { Debugger* debugger = Debugger::GetDebugger(runtime); debugger->StartDebugging(runtime); } JsContextRef context = JS_INVALID_REFERENCE; IfJsErrorFailLog(ChakraRTInterface::JsCreateContext(runtime, &context)); IfJsErrorFailLog(ChakraRTInterface::JsSetCurrentContext(context)); #endif #ifdef DEBUG ChakraRTInterface::SetCheckOpHelpersFlag(true); #endif #ifdef ENABLE_DEBUG_CONFIG_OPTIONS ChakraRTInterface::SetOOPCFGRegistrationFlag(false); #endif if (!WScriptJsrt::Initialize()) { IfFailGo(E_FAIL); } if (_fullpath(fullPath, fileName, _MAX_PATH) == nullptr) { IfFailGo(E_FAIL); } // canonicalize that path name to lower case for the profile storage // REVIEW: Assuming no utf8 characters here len = strlen(fullPath); for (size_t i = 0; i < len; i++) { fullPath[i] = (char)tolower(fullPath[i]); } if (HostConfigFlags::flags.GenerateLibraryByteCodeHeaderIsEnabled) { if (HostConfigFlags::flags.GenerateLibraryByteCodeHeader != nullptr && *HostConfigFlags::flags.GenerateLibraryByteCodeHeader != _u('\0')) { CHAR libraryName[_MAX_PATH]; CHAR ext[_MAX_EXT]; _splitpath_s(fullPath, NULL, 0, NULL, 0, libraryName, _countof(libraryName), ext, _countof(ext)); IfFailGo(CreateLibraryByteCodeHeader(fileContents, lengthBytes, HostConfigFlags::flags.GenerateLibraryByteCodeHeader, libraryName)); } else { fwprintf(stderr, _u("FATAL ERROR: -GenerateLibraryByteCodeHeader must provide the file name, i.e., -GenerateLibraryByteCodeHeader:<bytecode file name>, exiting\n")); IfFailGo(E_FAIL); } } else if (HostConfigFlags::flags.SerializedIsEnabled) { CreateAndRunSerializedScript(fileName, fileContents, fullPath); } else { IfFailGo(RunScript(fileName, fileContents, nullptr, fullPath)); } } Error: if (Debugger::debugger != nullptr) { Debugger::debugger->CompareOrWriteBaselineFile(fileName); Debugger::CloseDebugger(); } ChakraRTInterface::JsSetCurrentContext(nullptr); if (runtime != JS_INVALID_RUNTIME_HANDLE) { ChakraRTInterface::JsDisposeRuntime(runtime); } _flushall(); return hr; }
void Binder::CheckMscorlib() { const FieldOffsetCheck *pOffsets = MscorlibFieldOffsets; while (pOffsets->fieldID != FIELD__NIL) { FieldDesc *pFD = g_Mscorlib.FetchField(pOffsets->fieldID); DWORD offset = pFD->GetOffset(); if (!pFD->GetMethodTableOfEnclosingClass()->IsValueClass()) offset += sizeof(ObjHeader); _ASSERTE(offset == pOffsets->expectedOffset && "Managed class field offset does not match unmanaged class field offset"); pOffsets++; } const ClassSizeCheck *pSizes = MscorlibClassSizes; while (pSizes->classID != CLASS__NIL) { MethodTable *pMT = g_Mscorlib.FetchClass(pSizes->classID); DWORD size = pMT->GetClass()->GetNumInstanceFieldBytes(); DWORD expected = pSizes->expectedSize - sizeof(void*); _ASSERTE(size == expected && "Managed object size does not match unmanaged object size"); pSizes++; } // check the consistency of BCL and VM // note: it is not enabled by default because of it is time consuming and // changes the bootstrap sequence of the EE if (!g_pConfig->GetConfigDWORD(L"ConsistencyCheck", 0)) return; // // VM referencing BCL (mscorlib.h) // for (BinderClassID cID = (BinderClassID) 1; cID <= g_Mscorlib.m_cClassRIDs; cID = (BinderClassID) (cID + 1)) { if (g_Mscorlib.GetClassName(cID) != NULL) // Allow for CorSigElement entries with no classes g_Mscorlib.FetchClass(cID); } for (BinderMethodID mID = (BinderMethodID) 1; mID <= g_Mscorlib.m_cMethodRIDs; mID = (BinderMethodID) (mID + 1)) g_Mscorlib.FetchMethod(mID); for (BinderFieldID fID = (BinderFieldID) 1; fID <= g_Mscorlib.m_cFieldRIDs; fID = (BinderFieldID) (fID + 1)) g_Mscorlib.FetchField(fID); // // BCL referencing VM (ecall.cpp) // HRESULT hr = S_OK; Module *pModule = g_Mscorlib.m_pModule; IMDInternalImport *pInternalImport = pModule->GetMDImport(); HENUMInternal hEnum; // for all methods... IfFailGo(pInternalImport->EnumAllInit(mdtMethodDef, &hEnum)); for (;;) { mdTypeDef td; mdTypeDef tdClass; DWORD dwImplFlags; if (!pInternalImport->EnumNext(&hEnum, &td)) break; pInternalImport->GetMethodImplProps(td, NULL, &dwImplFlags); // ... that are internal calls ... if (!IsMiInternalCall(dwImplFlags)) continue; IfFailGo(pInternalImport->GetParentToken(td, &tdClass)); NameHandle className(pModule, tdClass); TypeHandle type; type = pModule->GetClassLoader()->LoadTypeHandle(&className, RETURN_ON_ERROR, FALSE); if (type.IsNull()) { LPCUTF8 pszName = pInternalImport->GetNameOfMethodDef(tdClass); OutputDebugStringA(pszName); OutputDebugStringA("\n"); _ASSERTE(false); } MethodDesc *pMD = type.AsMethodTable()->GetClass()->FindMethod(td);; _ASSERTE(pMD); // ... check that the method is in the fcall table. if (GetIDForMethod(pMD) == 0xffff) { LPCUTF8 pszName = pInternalImport->GetNameOfMethodDef(td); OutputDebugStringA(pszName); OutputDebugStringA("\n"); _ASSERTE(false); } } pInternalImport->EnumClose(&hEnum); ErrExit: _ASSERTE(SUCCEEDED(hr)); }
HRESULT Helpers::LoadScriptFromFile(LPCWSTR filename, LPCWSTR& contents, bool* isUtf8Out, LPCWSTR* contentsRawOut, UINT* lengthBytesOut, bool printFileOpenError) { HRESULT hr = S_OK; LPCWSTR contentsRaw = nullptr; UINT lengthBytes = 0; bool isUtf8 = false; contents = nullptr; FILE * file; // // Open the file as a binary file to prevent CRT from handling encoding, line-break conversions, // etc. // if (_wfopen_s(&file, filename, L"rb") != 0) { if (printFileOpenError) { DWORD lastError = GetLastError(); wchar_t wszBuff[512]; fwprintf(stderr, L"Error in opening file '%s' ", filename); wszBuff[0] = 0; if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, lastError, 0, wszBuff, _countof(wszBuff), nullptr)) { fwprintf(stderr, L": %s", wszBuff); } fwprintf(stderr, L"\n"); IfFailGo(E_FAIL); } else { return E_FAIL; } } // // Determine the file length, in bytes. // fseek(file, 0, SEEK_END); lengthBytes = ftell(file); fseek(file, 0, SEEK_SET); contentsRaw = (LPCWSTR)HeapAlloc(GetProcessHeap(), 0, lengthBytes + sizeof(WCHAR)); if (nullptr == contentsRaw) { fwprintf(stderr, L"out of memory"); IfFailGo(E_OUTOFMEMORY); } // // Read the entire content as a binary block. // fread((void*)contentsRaw, sizeof(char), lengthBytes, file); fclose(file); *(WCHAR*)((byte*)contentsRaw + lengthBytes) = L'\0'; // Null terminate it. Could be LPCWSTR. // // Read encoding, handling any conversion to Unicode. // // Warning: The UNICODE buffer for parsing is supposed to be provided by the host. // This is not a complete read of the encoding. Some encodings like UTF7, UTF1, EBCDIC, SCSU, BOCU could be // wrongly classified as ANSI // byte * pRawBytes = (byte*)contentsRaw; if ((0xEF == *pRawBytes && 0xBB == *(pRawBytes + 1) && 0xBF == *(pRawBytes + 2))) { isUtf8 = true; } else if (0xFFFE == *contentsRaw || 0x0000 == *contentsRaw && 0xFEFF == *(contentsRaw + 1)) { // unicode unsupported fwprintf(stderr, L"unsupported file encoding"); IfFailGo(E_UNEXPECTED); } else if (0xFEFF == *contentsRaw) { // unicode LE contents = contentsRaw; } else { // Assume UTF8 isUtf8 = true; } if (isUtf8) { utf8::DecodeOptions decodeOptions = utf8::doAllowInvalidWCHARs; UINT cUtf16Chars = utf8::ByteIndexIntoCharacterIndex(pRawBytes, lengthBytes, decodeOptions); contents = (LPCWSTR)HeapAlloc(GetProcessHeap(), 0, (cUtf16Chars + 1) * sizeof(WCHAR)); if (nullptr == contents) { fwprintf(stderr, L"out of memory"); IfFailGo(E_OUTOFMEMORY); } utf8::DecodeIntoAndNullTerminate((wchar_t*) contents, pRawBytes, cUtf16Chars, decodeOptions); } Error: if (SUCCEEDED(hr) && isUtf8Out) { Assert(contentsRawOut); Assert(lengthBytesOut); *isUtf8Out = isUtf8; *contentsRawOut = contentsRaw; *lengthBytesOut = lengthBytes; } else if (contentsRaw && (contentsRaw != contents)) // Otherwise contentsRaw is lost. Free it if it is different to contents. { HeapFree(GetProcessHeap(), 0, (void*)contentsRaw); } if (contents && FAILED(hr)) { HeapFree(GetProcessHeap(), 0, (void*)contents); contents = nullptr; } return hr; }
HRESULT _CountBytesOfOneArg( PCCOR_SIGNATURE pbSig, ULONG *pcbTotal) // Initially, *pcbTotal contains the remaining size of the sig blob { ULONG cb; ULONG cbTotal=0; ULONG cbTotalMax; CorElementType ulElementType; ULONG ulData; ULONG ulTemp; int iData; mdToken tk; ULONG cArg; ULONG callingconv; ULONG cArgsIndex; HRESULT hr = NOERROR; if(pcbTotal==NULL) return E_FAIL; cbTotalMax = *pcbTotal; CHECK_REMAINDER; cbTotal = CorSigUncompressElementType(pbSig, &ulElementType); while (CorIsModifierElementType((CorElementType) ulElementType)) { CHECK_REMAINDER; cbTotal += CorSigUncompressElementType(&pbSig[cbTotal], &ulElementType); } switch (ulElementType) { case ELEMENT_TYPE_SZARRAY: case 0x1e /* obsolete */: // skip over base type CHECK_REMAINDER; cb = cbTotalMax - cbTotal; IfFailGo( _CountBytesOfOneArg(&pbSig[cbTotal], &cb) ); cbTotal += cb; break; case ELEMENT_TYPE_FNPTR: CHECK_REMAINDER; cbTotal += CorSigUncompressData (&pbSig[cbTotal], &callingconv); // remember number of bytes to represent the arg counts CHECK_REMAINDER; cbTotal += CorSigUncompressData (&pbSig[cbTotal], &cArg); // how many bytes to represent the return type CHECK_REMAINDER; cb = cbTotalMax - cbTotal; IfFailGo( _CountBytesOfOneArg( &pbSig[cbTotal], &cb) ); cbTotal += cb; // loop through argument for (cArgsIndex = 0; cArgsIndex < cArg; cArgsIndex++) { CHECK_REMAINDER; cb = cbTotalMax - cbTotal; IfFailGo( _CountBytesOfOneArg( &pbSig[cbTotal], &cb) ); cbTotal += cb; } break; case ELEMENT_TYPE_ARRAY: // syntax : ARRAY BaseType <rank> [i size_1... size_i] [j lowerbound_1 ... lowerbound_j] // skip over base type CHECK_REMAINDER; cb = cbTotalMax - cbTotal; IfFailGo( _CountBytesOfOneArg(&pbSig[cbTotal], &cb) ); cbTotal += cb; // Parse for the rank CHECK_REMAINDER; cbTotal += CorSigUncompressData(&pbSig[cbTotal], &ulData); // if rank == 0, we are done if (ulData == 0) break; // any size of dimension specified? CHECK_REMAINDER; cbTotal += CorSigUncompressData(&pbSig[cbTotal], &ulData); while (ulData--) { CHECK_REMAINDER; cbTotal += CorSigUncompressData(&pbSig[cbTotal], &ulTemp); } // any lower bound specified? CHECK_REMAINDER; cbTotal += CorSigUncompressData(&pbSig[cbTotal], &ulData); while (ulData--) { CHECK_REMAINDER; cbTotal += CorSigUncompressSignedInt(&pbSig[cbTotal], &iData); } break; case ELEMENT_TYPE_VALUETYPE: case ELEMENT_TYPE_CLASS: case ELEMENT_TYPE_CMOD_REQD: case ELEMENT_TYPE_CMOD_OPT: // count the bytes for the token compression CHECK_REMAINDER; cbTotal += CorSigUncompressToken(&pbSig[cbTotal], &tk); if ( ulElementType == ELEMENT_TYPE_CMOD_REQD || ulElementType == ELEMENT_TYPE_CMOD_OPT) { // skip over base type CHECK_REMAINDER; cb = cbTotalMax - cbTotal; IfFailGo( _CountBytesOfOneArg(&pbSig[cbTotal], &cb) ); cbTotal += cb; } break; default: break; } *pcbTotal = cbTotal; ErrExit: return hr; }
//***************************************************************************** // copy fixed part of VarArg signature to a buffer //***************************************************************************** HRESULT _GetFixedSigOfVarArg( // S_OK or error. PCCOR_SIGNATURE pvSigBlob, // [IN] point to a blob of COM+ method signature ULONG cbSigBlob, // [IN] size of signature CQuickBytes *pqbSig, // [OUT] output buffer for fixed part of VarArg Signature ULONG *pcbSigBlob) // [OUT] number of bytes written to the above output buffer { HRESULT hr = NOERROR; ULONG cbCalling; ULONG cbTyArgsNumber = 0; // number of bytes to store the type arg count (generics only) ULONG cbArgsNumber; // number of bytes to store the original arg count ULONG cbArgsNumberTemp; // number of bytes to store the fixed arg count ULONG cbTotal = 0; // total of number bytes for return type + all fixed arguments ULONG cbCur = 0; // index through the pvSigBlob ULONG cb; ULONG cArg; ULONG cTyArg; ULONG callingconv; ULONG cArgsIndex; CorElementType ulElementType; BYTE *pbSig; _ASSERTE (pvSigBlob && pcbSigBlob); // remember the number of bytes to represent the calling convention cbCalling = CorSigUncompressData (pvSigBlob, &callingconv); if (cbCalling == ((ULONG)(-1))) { return E_INVALIDARG; } _ASSERTE (isCallConv(callingconv, IMAGE_CEE_CS_CALLCONV_VARARG)); cbCur += cbCalling; if (callingconv & IMAGE_CEE_CS_CALLCONV_GENERIC) { cbTyArgsNumber = CorSigUncompressData(&pvSigBlob[cbCur], &cTyArg); if (cbTyArgsNumber == ((ULONG)(-1))) { return E_INVALIDARG; } cbCur += cbTyArgsNumber; } // remember number of bytes to represent the arg counts cbArgsNumber= CorSigUncompressData (&pvSigBlob[cbCur], &cArg); if (cbArgsNumber == ((ULONG)(-1))) { return E_INVALIDARG; } cbCur += cbArgsNumber; // how many bytes to represent the return type cb = cbSigBlob-cbCur; IfFailGo( _CountBytesOfOneArg( &pvSigBlob[cbCur], &cb) ); cbCur += cb; cbTotal += cb; // loop through argument until we found ELEMENT_TYPE_SENTINEL or run // out of arguments for (cArgsIndex = 0; cArgsIndex < cArg; cArgsIndex++) { _ASSERTE(cbCur < cbSigBlob); // peak the outer most ELEMENT_TYPE_* CorSigUncompressElementType (&pvSigBlob[cbCur], &ulElementType); if (ulElementType == ELEMENT_TYPE_SENTINEL) break; cb = cbSigBlob-cbCur; IfFailGo( _CountBytesOfOneArg( &pvSigBlob[cbCur], &cb) ); cbTotal += cb; cbCur += cb; } cbArgsNumberTemp = CorSigCompressData(cArgsIndex, &cArg); // now cbCalling : the number of bytes needed to store the calling convention // cbArgNumberTemp : number of bytes to store the fixed arg count // cbTotal : the number of bytes to store the ret and fixed arguments *pcbSigBlob = cbCalling + cbArgsNumberTemp + cbTotal; // resize the buffer IfFailGo( pqbSig->ReSizeNoThrow(*pcbSigBlob) ); pbSig = (BYTE *)pqbSig->Ptr(); // copy over the calling convention cb = CorSigCompressData(callingconv, pbSig); // copy over the fixed arg count cbArgsNumberTemp = CorSigCompressData(cArgsIndex, &pbSig[cb]); // copy over the fixed args + ret type memcpy(&pbSig[cb + cbArgsNumberTemp], &pvSigBlob[cbCalling + cbArgsNumber], cbTotal); ErrExit: return hr; }
//***************************************************************************** // Remove a RegMeta pointer from the loaded module list //***************************************************************************** // static HRESULT LOADEDMODULES::ResolveTypeRefWithLoadedModules( mdTypeRef tkTypeRef, // [IN] TypeRef to be resolved. RegMeta * pTypeRefRegMeta, // [IN] Scope in which the TypeRef is defined. IMetaModelCommon * pTypeRefScope, // [IN] Scope in which the TypeRef is defined. REFIID riid, // [IN] iid for the return interface. IUnknown ** ppIScope, // [OUT] Return interface. mdTypeDef * ptd) // [OUT] TypeDef corresponding the TypeRef. { HRESULT hr = NOERROR; RegMeta * pRegMeta; CQuickArray<mdTypeRef> cqaNesters; CQuickArray<LPCUTF8> cqaNesterNamespaces; CQuickArray<LPCUTF8> cqaNesterNames; IfFailGo(InitializeStatics()); { LOCKREAD(); // Get the Nesting hierarchy. IfFailGo(ImportHelper::GetNesterHierarchy( pTypeRefScope, tkTypeRef, cqaNesters, cqaNesterNamespaces, cqaNesterNames)); int count = s_pLoadedModules->Count(); for (int index = 0; index < count; index++) { pRegMeta = (*s_pLoadedModules)[index]; { // Do not lock the TypeRef RegMeta (again), as it is already locked for read by the caller. // The code:UTSemReadWrite will block ReadLock even for thread holding already the read lock if // some other thread is waiting for WriteLock on the same lock. That would cause dead-lock if we // try to lock for read again here. CMDSemReadWrite cSemRegMeta((pRegMeta == pTypeRefRegMeta) ? NULL : pRegMeta->GetReaderWriterLock()); IfFailGo(cSemRegMeta.LockRead()); hr = ImportHelper::FindNestedTypeDef( pRegMeta->GetMiniMd(), cqaNesterNamespaces, cqaNesterNames, mdTokenNil, ptd); } if (hr == CLDB_E_RECORD_NOTFOUND) { // Process next MetaData module continue; } IfFailGo(hr); // Found a loaded module containing the TypeDef. IfFailGo(pRegMeta->QueryInterface(riid, (void **)ppIScope)); break; } } if (FAILED(hr)) { // cannot find the match! hr = E_FAIL; } ErrExit: return hr; } // LOADEDMODULES::ResolveTypeRefWithLoadedModules
//***************************************************************************** // Determine what the size of the saved data will be. //***************************************************************************** __checkReturn HRESULT CLiteWeightStgdbRW::GetSaveSize(// S_OK or error. CorSaveSize fSave, // Quick or accurate? UINT32 *pcbSaveSize, // Put the size here. MetaDataReorderingOptions reorderingOptions, CorProfileData *pProfileData) // Profile data for working set optimization { HRESULT hr = S_OK; // A result. UINT32 cbTotal = 0; // The total size. UINT32 cbSize = 0; // Size of a component. m_cbSaveSize = 0; // Allocate stream list if not already done. if (m_pStreamList == NULL) { IfNullGo(m_pStreamList = new (nothrow) STORAGESTREAMLST); } else { m_pStreamList->Clear(); } // Make sure the user string pool is not empty. An empty user string pool causes // problems with edit and continue if (m_MiniMd.m_UserStringHeap.GetUnalignedSize() <= 1) { if (!IsENCDelta(m_MiniMd.m_OptionValue.m_UpdateMode) && !m_MiniMd.IsMinimalDelta()) { BYTE rgData[] = {' ', 0, 0}; UINT32 nIndex_Ignore; IfFailGo(m_MiniMd.PutUserString( MetaData::DataBlob(rgData, sizeof(rgData)), &nIndex_Ignore)); } } // If we're saving a delta metadata, figure out how much space it will take to // save the minimal metadata stream (used only to identify that we have a delta // metadata... nothing should be in that stream. if ((m_MiniMd.m_OptionValue.m_UpdateMode & MDUpdateMask) == MDUpdateDelta) { IfFailGo(AddStreamToList(0, MINIMAL_MD_STREAM)); // Ask the storage system to add stream fixed overhead. IfFailGo(TiggerStorage::GetStreamSaveSize(MINIMAL_MD_STREAM, 0, &cbSize)); cbTotal += cbSize; } if (reorderingOptions & ReArrangeStringPool) { if (pProfileData != NULL) { UINT32 cbHotSize = 0; // Size of pool data. UINT32 cbStream; // Size of just the stream. DWORD bCompressed; // Will the stream be compressed data? // Ask the metadata to size its hot data. IfFailGo(m_MiniMd.GetSaveSize(fSave, &cbHotSize, &bCompressed, reorderingOptions, pProfileData)); cbStream = cbHotSize; m_bSaveCompressed = bCompressed; if (cbHotSize != 0) { // Add this item to the save list. IfFailGo(AddStreamToList(cbHotSize, HOT_MODEL_STREAM)); // Ask the storage system to add stream fixed overhead. IfFailGo(TiggerStorage::GetStreamSaveSize(HOT_MODEL_STREAM, cbHotSize, &cbHotSize)); // Log the size info. LOG((LF_METADATA, LL_INFO10, "Metadata: GetSaveSize for %ls: %d data, %d total.\n", HOT_MODEL_STREAM, cbStream, cbHotSize)); cbTotal += cbHotSize; } } // get string pool save size IfFailGo(GetPoolSaveSize(STRING_POOL_STREAM, MDPoolStrings, &cbSize)); cbTotal += cbSize; } // Query the MiniMd for its size. IfFailGo(GetTablesSaveSize(fSave, &cbSize, reorderingOptions, pProfileData)); cbTotal += cbSize; // Get the pools' sizes. if( !(reorderingOptions & ReArrangeStringPool) ) { IfFailGo(GetPoolSaveSize(STRING_POOL_STREAM, MDPoolStrings, &cbSize)); cbTotal += cbSize; } IfFailGo(GetPoolSaveSize(US_BLOB_POOL_STREAM, MDPoolUSBlobs, &cbSize)); cbTotal += cbSize; IfFailGo(GetPoolSaveSize(GUID_POOL_STREAM, MDPoolGuids, &cbSize)); cbTotal += cbSize; IfFailGo(GetPoolSaveSize(BLOB_POOL_STREAM, MDPoolBlobs, &cbSize)); cbTotal += cbSize; // Finally, ask the storage system to add fixed overhead it needs for the // file format. The overhead of each stream has already be calculated as // part of GetStreamSaveSize. What's left is the signature and header // fixed size overhead. IfFailGo(TiggerStorage::GetStorageSaveSize((ULONG *)&cbTotal, 0, m_MiniMd.m_OptionValue.m_RuntimeVersion)); // Log the size info. LOG((LF_METADATA, LL_INFO10, "Metadata: GetSaveSize total is %d.\n", cbTotal)); // The list of streams that will be saved are now in the stream save list. // Next step is to walk that list and fill out the correct offsets. This is // done here so that the data can be streamed without fixing up the header. TiggerStorage::CalcOffsets(m_pStreamList, 0, m_MiniMd.m_OptionValue.m_RuntimeVersion); if (pcbSaveSize != NULL) { *pcbSaveSize = cbTotal; } // Don't cache the value for the EnC case if (!IsENCDelta(m_MiniMd.m_OptionValue.m_UpdateMode)) m_cbSaveSize = cbTotal; ErrExit: return hr; } // CLiteWeightStgdbRW::GetSaveSize
//***************************************************************************** // Enumerate Sym.TypeDef. //***************************************************************************** STDMETHODIMP RegMeta::EnumTypeDefs( HCORENUM *phEnum, // Pointer to the enumerator. mdTypeDef rTypeDefs[], // Put TypeDefs here. ULONG cMax, // Max TypeDefs to put. ULONG *pcTypeDefs) // Put # put here. { HRESULT hr = S_OK; BEGIN_ENTRYPOINT_NOTHROW; HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); HENUMInternal *pEnum; LOG((LOGMD, "RegMeta::EnumTypeDefs(0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", phEnum, rTypeDefs, cMax, pcTypeDefs)); START_MD_PERF(); LOCKREAD(); if ( *ppmdEnum == 0 ) { // instantiating a new ENUM CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); if (pMiniMd->HasDelete() && ((m_OptionValue.m_ImportOption & MDImportOptionAllTypeDefs) == 0)) { IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtTypeDef, &pEnum) ); // add all Types to the dynamic array if name is not _Delete for (ULONG index = 2; index <= pMiniMd->getCountTypeDefs(); index ++ ) { TypeDefRec *pRec; IfFailGo(pMiniMd->GetTypeDefRecord(index, &pRec)); LPCSTR szTypeDefName; IfFailGo(pMiniMd->getNameOfTypeDef(pRec, &szTypeDefName)); if (IsDeletedName(szTypeDefName)) { continue; } IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtTypeDef) ) ); } } else { // create the enumerator IfFailGo( HENUMInternal::CreateSimpleEnum( mdtTypeDef, 2, pMiniMd->getCountTypeDefs() + 1, &pEnum) ); } // set the output parameter *ppmdEnum = pEnum; } else { pEnum = *ppmdEnum; } // we can only fill the minimun of what caller asked for or what we have left hr = HENUMInternal::EnumWithCount(pEnum, cMax, rTypeDefs, pcTypeDefs); ErrExit: HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); STOP_MD_PERF(EnumTypeDefs); END_ENTRYPOINT_NOTHROW; return hr; } // RegMeta::EnumTypeDefs
//***************************************************************************** // Get the save size of the metadata tables. Also adds the tables stream to // the list of streams to be saved. //***************************************************************************** __checkReturn HRESULT CLiteWeightStgdbRW::GetTablesSaveSize( CorSaveSize fSave, UINT32 *pcbSaveSize, MetaDataReorderingOptions reorderingOptions, CorProfileData *pProfileData) // Add pool data to this value. { UINT32 cbSize = 0; // Size of pool data. UINT32 cbHotSize = 0; // Size of pool data. UINT32 cbStream; // Size of just the stream. DWORD bCompressed; // Will the stream be compressed data? LPCWSTR szName; // What will the name of the pool be? HRESULT hr; *pcbSaveSize = 0; if( !(reorderingOptions & ReArrangeStringPool) ) { if (pProfileData != NULL) { // Ask the metadata to size its hot data. IfFailGo(m_MiniMd.GetSaveSize(fSave, &cbHotSize, &bCompressed, reorderingOptions, pProfileData)); cbStream = cbHotSize; m_bSaveCompressed = bCompressed; if (cbHotSize != 0) { szName = HOT_MODEL_STREAM; // Add this item to the save list. IfFailGo(AddStreamToList(cbHotSize, szName)); // Ask the storage system to add stream fixed overhead. IfFailGo(TiggerStorage::GetStreamSaveSize(szName, cbHotSize, &cbHotSize)); // Log the size info. LOG((LF_METADATA, LL_INFO10, "Metadata: GetSaveSize for %ls: %d data, %d total.\n", szName, cbStream, cbHotSize)); } } } // Ask the metadata to size its data. IfFailGo(m_MiniMd.GetSaveSize(fSave, &cbSize, &bCompressed)); cbStream = cbSize; m_bSaveCompressed = bCompressed; szName = m_bSaveCompressed ? COMPRESSED_MODEL_STREAM : ENC_MODEL_STREAM; // Add this item to the save list. IfFailGo(AddStreamToList(cbSize, szName)); // Ask the storage system to add stream fixed overhead. IfFailGo(TiggerStorage::GetStreamSaveSize(szName, cbSize, &cbSize)); // Log the size info. LOG((LF_METADATA, LL_INFO10, "Metadata: GetSaveSize for %ls: %d data, %d total.\n", szName, cbStream, cbSize)); // Give the size of the pool to the caller's total. *pcbSaveSize = cbHotSize + cbSize; ErrExit: return hr; } // CLiteWeightStgdbRW::GetTablesSaveSize
//***************************************************************************** // Enumerate Sym.InterfaceImpl where Coclass == td //***************************************************************************** STDMETHODIMP RegMeta::EnumInterfaceImpls( HCORENUM *phEnum, // Pointer to the enum. mdTypeDef td, // TypeDef to scope the enumeration. mdInterfaceImpl rImpls[], // Put InterfaceImpls here. ULONG cMax, // Max InterfaceImpls to put. ULONG *pcImpls) // Put # put here. { HRESULT hr = S_OK; BEGIN_ENTRYPOINT_NOTHROW; HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); ULONG ridStart; ULONG ridEnd; HENUMInternal *pEnum; InterfaceImplRec *pRec; ULONG index; LOG((LOGMD, "RegMeta::EnumInterfaceImpls(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", phEnum, td, rImpls, cMax, pcImpls)); START_MD_PERF(); LOCKREAD(); _ASSERTE(TypeFromToken(td) == mdtTypeDef); if ( *ppmdEnum == 0 ) { // instantiating a new ENUM CMiniMdRW *pMiniMd = &(m_pStgdb->m_MiniMd); if ( pMiniMd->IsSorted( TBL_InterfaceImpl ) ) { IfFailGo(pMiniMd->getInterfaceImplsForTypeDef(RidFromToken(td), &ridEnd, &ridStart)); IfFailGo( HENUMInternal::CreateSimpleEnum( mdtInterfaceImpl, ridStart, ridEnd, &pEnum) ); } else { // table is not sorted so we have to create dynmaic array // create the dynamic enumerator // ridStart = 1; ridEnd = pMiniMd->getCountInterfaceImpls() + 1; IfFailGo( HENUMInternal::CreateDynamicArrayEnum( mdtInterfaceImpl, &pEnum) ); for (index = ridStart; index < ridEnd; index ++ ) { IfFailGo(pMiniMd->GetInterfaceImplRecord(index, &pRec)); if ( td == pMiniMd->getClassOfInterfaceImpl(pRec) ) { IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtInterfaceImpl) ) ); } } } // set the output parameter *ppmdEnum = pEnum; } else { pEnum = *ppmdEnum; } // fill the output token buffer hr = HENUMInternal::EnumWithCount(pEnum, cMax, rImpls, pcImpls); ErrExit: HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); STOP_MD_PERF(EnumInterfaceImpls); END_ENTRYPOINT_NOTHROW; return hr; } // RegMeta::EnumInterfaceImpls
//***************************************************************************** // Save the metadata to a file. //***************************************************************************** __checkReturn HRESULT CLiteWeightStgdbRW::Save( LPCWSTR szDatabase, // Name of file to which to save. DWORD dwSaveFlags) // Flags for the save. { TiggerStorage * pStorage = NULL; // IStorage object. StgIO * pStgIO = NULL; // Backing storage. HRESULT hr = S_OK; if (m_wszFileName == NULL) { if (szDatabase == NULL) { // Make sure that a NULL is not passed in the first time around. _ASSERTE(!"Not allowed to pass a NULL for filename on the first call to Save."); return E_INVALIDARG; } else { // Save the file name. IfFailGo(SetFileName(szDatabase)); } } else if ((szDatabase != NULL) && (SString::_wcsicmp(szDatabase, m_wszFileName) != 0)) { // Save the file name. IfFailGo(SetFileName(szDatabase)); } // Sanity check the name. if (!IsValidFileNameLength(m_wszFileName)) { IfFailGo(E_INVALIDARG); } m_eFileType = FILETYPE_CLB; // Allocate a new storage object. IfNullGo(pStgIO = new (nothrow) StgIO); // Create the output file. IfFailGo(pStgIO->Open(m_wszFileName, DBPROP_TMODEF_DFTWRITEMASK, 0,0, // pbData, cbData 0, // IStream* 0)); // LPSecurityAttributes // Allocate an IStorage object to use. IfNullGo(pStorage = new (nothrow) TiggerStorage); // Init the storage object on the i/o system. OptionValue ov; IfFailGo(m_MiniMd.GetOption(&ov)); IfFailGo(pStorage->Init(pStgIO, ov.m_RuntimeVersion)); // Save the data. IfFailGo(SaveToStorage(pStorage)); ErrExit: if (pStgIO != NULL) pStgIO->Release(); if (pStorage != NULL) delete pStorage; return hr; } // CLiteWeightStgdbRW::Save
STDMETHODIMP RegMeta::EnumMethodSpecs( HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. mdToken tkOwner, // [IN] MethodDef or MemberRef whose MethodSpecs are requested mdMethodSpec rTokens[], // [OUT] Put MethodSpecs here. ULONG cMaxTokens, // [IN] Max tokens to put. ULONG *pcTokens) // [OUT] Put actual count here. { HRESULT hr = S_OK; BEGIN_ENTRYPOINT_NOTHROW; HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); ULONG ridStart; ULONG ridEnd; HENUMInternal *pEnum; MethodSpecRec *pRec; ULONG index; CMiniMdRW *pMiniMd = NULL; LOG((LOGMD, "RegMeta::EnumMethodSpecs(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", phEnum, tkOwner, rTokens, cMaxTokens, pcTokens)); START_MD_PERF(); LOCKREAD(); pMiniMd = &(m_pStgdb->m_MiniMd); // See if this version of the metadata can do Generics if (!pMiniMd->SupportsGenerics()) { if (pcTokens) *pcTokens = 0; hr = S_FALSE; goto ErrExit; } _ASSERTE(RidFromToken(tkOwner)==0 || TypeFromToken(tkOwner) == mdtMethodDef || TypeFromToken(tkOwner) == mdtMemberRef); if ( *ppmdEnum == 0 ) { // instantiating a new ENUM if(RidFromToken(tkOwner)==0) // enumerate all MethodSpecs { ridStart = 1; ridEnd = pMiniMd->getCountMethodSpecs() + 1; IfFailGo( HENUMInternal::CreateSimpleEnum( mdtMethodSpec, ridStart, ridEnd, &pEnum) ); } else { //@todo GENERICS: review this. Are we expecting a sorted table or not? if ( pMiniMd->IsSorted( TBL_MethodSpec ) ) { if (TypeFromToken(tkOwner) == mdtMemberRef) { IfFailGo(pMiniMd->getMethodSpecsForMemberRef(RidFromToken(tkOwner), &ridEnd, &ridStart)); } else { IfFailGo(pMiniMd->getMethodSpecsForMethodDef(RidFromToken(tkOwner), &ridEnd, &ridStart)); } IfFailGo( HENUMInternal::CreateSimpleEnum(mdtMethodSpec, ridStart, ridEnd, &pEnum) ); } else { // table is not sorted so we have to create dynamic array // create the dynamic enumerator // ridStart = 1; ridEnd = pMiniMd->getCountMethodSpecs() + 1; IfFailGo( HENUMInternal::CreateDynamicArrayEnum(mdtMethodSpec, &pEnum) ); for (index = ridStart; index < ridEnd; index ++ ) { IfFailGo(pMiniMd->GetMethodSpecRecord(index, &pRec)); if ( tkOwner == pMiniMd->getMethodOfMethodSpec(pRec) ) { IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtMethodSpec) ) ); } } } } // set the output parameter *ppmdEnum = pEnum; } else { pEnum = *ppmdEnum; } // fill the output token buffer hr = HENUMInternal::EnumWithCount(pEnum, cMaxTokens, rTokens, pcTokens); ErrExit: HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); STOP_MD_PERF(EnumMethodSpecs); END_ENTRYPOINT_NOTHROW; return hr; } // STDMETHODIMP RegMeta::EnumMethodSpecs()
//***************************************************************************** // translating signature from one scope to another scope // // Implements public API code:IMetaDataEmit::TranslateSigWithScope. // Implements internal API code:IMetaDataHelper::TranslateSigWithScope. //***************************************************************************** STDMETHODIMP RegMeta::TranslateSigWithScope( // S_OK or error. IMetaDataAssemblyImport *pAssemImport, // [IN] importing assembly interface const void *pbHashValue, // [IN] Hash Blob for Assembly. ULONG cbHashValue, // [IN] Count of bytes. IMetaDataImport *pImport, // [IN] importing interface PCCOR_SIGNATURE pbSigBlob, // [IN] signature in the importing scope ULONG cbSigBlob, // [IN] count of bytes of signature IMetaDataAssemblyEmit *pAssemEmit,// [IN] emit assembly interface IMetaDataEmit *pEmit, // [IN] emit interface PCOR_SIGNATURE pvTranslatedSig, // [OUT] buffer to hold translated signature ULONG cbTranslatedSigMax, ULONG *pcbTranslatedSig) // [OUT] count of bytes in the translated signature { #ifdef FEATURE_METADATA_EMIT HRESULT hr = S_OK; IMDCommon *pAssemImportMDCommon = NULL; IMDCommon *pImportMDCommon = NULL; BEGIN_ENTRYPOINT_NOTHROW; RegMeta *pRegMetaAssemEmit = static_cast<RegMeta*>(pAssemEmit); RegMeta *pRegMetaEmit = NULL; CQuickBytes qkSigEmit; ULONG cbEmit; pRegMetaEmit = static_cast<RegMeta*>(pEmit); { // This function can cause new TypeRef being introduced. LOCKWRITE(); IfFailGo(m_pStgdb->m_MiniMd.PreUpdate()); _ASSERTE(pvTranslatedSig && pcbTranslatedSig); if (pAssemImport) { IfFailGo(pAssemImport->QueryInterface(IID_IMDCommon, (void**)&pAssemImportMDCommon)); } IMetaModelCommon *pAssemImportMetaModelCommon = pAssemImportMDCommon ? pAssemImportMDCommon->GetMetaModelCommon() : 0; IfFailGo(pImport->QueryInterface(IID_IMDCommon, (void**)&pImportMDCommon)); IMetaModelCommon *pImportMetaModelCommon = pImportMDCommon->GetMetaModelCommon(); IfFailGo( ImportHelper::MergeUpdateTokenInSig( // S_OK or error. pRegMetaAssemEmit ? &(pRegMetaAssemEmit->m_pStgdb->m_MiniMd) : 0, // The assembly emit scope. &(pRegMetaEmit->m_pStgdb->m_MiniMd), // The emit scope. pAssemImportMetaModelCommon, // Assembly where the signature is from. pbHashValue, // Hash value for the import assembly. cbHashValue, // Size in bytes. pImportMetaModelCommon, // The scope where signature is from. pbSigBlob, // signature from the imported scope NULL, // Internal OID mapping structure. &qkSigEmit, // [OUT] translated signature 0, // start from first byte of the signature 0, // don't care how many bytes consumed &cbEmit)); // [OUT] total number of bytes write to pqkSigEmit memcpy(pvTranslatedSig, qkSigEmit.Ptr(), cbEmit > cbTranslatedSigMax ? cbTranslatedSigMax :cbEmit ); *pcbTranslatedSig = cbEmit; if (cbEmit > cbTranslatedSigMax) hr = CLDB_S_TRUNCATION; } ErrExit: END_ENTRYPOINT_NOTHROW; if (pAssemImportMDCommon) pAssemImportMDCommon->Release(); if (pImportMDCommon) pImportMDCommon->Release(); return hr; #else //!FEATURE_METADATA_EMIT return E_NOTIMPL; #endif //!FEATURE_METADATA_EMIT } // RegMeta::TranslateSigWithScope
STDMETHODIMP RegMeta::EnumGenericParamConstraints( HCORENUM *phEnum, // [IN|OUT] Pointer to the enum. mdGenericParam tkOwner, // [IN] GenericParam whose constraints are requested mdGenericParamConstraint rTokens[], // [OUT] Put GenericParamConstraints here. ULONG cMaxTokens, // [IN] Max GenericParamConstraints to put. ULONG *pcTokens) // [OUT] Put # of tokens here. { HRESULT hr = S_OK; BEGIN_ENTRYPOINT_NOTHROW; HENUMInternal **ppmdEnum = reinterpret_cast<HENUMInternal **> (phEnum); ULONG ridStart; ULONG ridEnd; HENUMInternal *pEnum; GenericParamConstraintRec *pRec; ULONG index; CMiniMdRW *pMiniMd = NULL; LOG((LOGMD, "RegMeta::EnumGenericParamConstraints(0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n", phEnum, tkOwner, rTokens, cMaxTokens, pcTokens)); START_MD_PERF(); LOCKREAD(); pMiniMd = &(m_pStgdb->m_MiniMd); if(TypeFromToken(tkOwner) != mdtGenericParam) IfFailGo(META_E_BAD_INPUT_PARAMETER); // See if this version of the metadata can do Generics if (!pMiniMd->SupportsGenerics()) { if (pcTokens) *pcTokens = 0; hr = S_FALSE; goto ErrExit; } if ( *ppmdEnum == 0 ) { // instantiating a new ENUM //<TODO> GENERICS: review this. Are we expecting a sorted table or not? </TODO> if ( pMiniMd->IsSorted( TBL_GenericParamConstraint ) ) { IfFailGo(pMiniMd->getGenericParamConstraintsForGenericParam(RidFromToken(tkOwner), &ridEnd, &ridStart)); IfFailGo( HENUMInternal::CreateSimpleEnum(mdtGenericParamConstraint, ridStart, ridEnd, &pEnum) ); } else { // table is not sorted so we have to create dynamic array // create the dynamic enumerator // ridStart = 1; ridEnd = pMiniMd->getCountGenericParamConstraints() + 1; IfFailGo( HENUMInternal::CreateDynamicArrayEnum(mdtGenericParamConstraint, &pEnum)); for (index = ridStart; index < ridEnd; index ++ ) { IfFailGo(pMiniMd->GetGenericParamConstraintRecord(index, &pRec)); if ( tkOwner == pMiniMd->getOwnerOfGenericParamConstraint(pRec)) { IfFailGo( HENUMInternal::AddElementToEnum(pEnum, TokenFromRid(index, mdtGenericParamConstraint))); } } } // set the output parameter *ppmdEnum = pEnum; } else { pEnum = *ppmdEnum; } // fill the output token buffer hr = HENUMInternal::EnumWithCount(pEnum, cMaxTokens, rTokens, pcTokens); ErrExit: HENUMInternal::DestroyEnumIfEmpty(ppmdEnum); STOP_MD_PERF(EnumGenericParamConstraints); END_ENTRYPOINT_NOTHROW; return hr; }
HRESULT Helpers::LoadScriptFromFile(LPCSTR filenameToLoad, LPCSTR& contents, UINT* lengthBytesOut /*= nullptr*/, std::string* fullPath /*= nullptr*/, bool shouldMute /*=false */) { static char sHostApplicationPathBuffer[MAX_URI_LENGTH]; static uint sHostApplicationPathBufferLength = (uint) -1; char combinedPathBuffer[MAX_URI_LENGTH]; HRESULT hr = S_OK; BYTE * pRawBytes = nullptr; BYTE * pRawBytesFromMap = nullptr; UINT lengthBytes = 0; contents = nullptr; FILE * file = NULL; size_t bufferLength = 0; LPCSTR filename = fullPath == nullptr ? filenameToLoad : LPCSTR(fullPath->c_str()); if (sHostApplicationPathBufferLength == (uint)-1) { // consider incoming filename as the host app and base its' path for others sHostApplicationPathBufferLength = GetPathNameLocation(filename); if (sHostApplicationPathBufferLength == -1) { // host app has no path info. (it must be located on current folder!) sHostApplicationPathBufferLength = 0; } else { sHostApplicationPathBufferLength += 1; Assert(sHostApplicationPathBufferLength < MAX_URI_LENGTH); // save host app's path and fix the path separator for platform pathcpy(sHostApplicationPathBuffer, filename, sHostApplicationPathBufferLength); } sHostApplicationPathBuffer[sHostApplicationPathBufferLength] = char(0); } else if (filename[0] != '/' && filename[0] != '\\' && fullPath == nullptr) // make sure it's not a full path { // concat host path and filename uint len = ConcatPath(sHostApplicationPathBuffer, sHostApplicationPathBufferLength, filename, combinedPathBuffer, MAX_URI_LENGTH); if (len == (uint)-1) { hr = E_FAIL; goto Error; } filename = combinedPathBuffer; } // check if have it registered AutoString *data; if (SourceMap::Find(filenameToLoad, strlen(filenameToLoad), &data) || SourceMap::Find(filename, strlen(filename), &data)) { pRawBytesFromMap = (BYTE*) data->GetString(); lengthBytes = (UINT) data->GetLength(); } else { // Open the file as a binary file to prevent CRT from handling encoding, line-break conversions, // etc. if (fopen_s(&file, filename, "rb") != 0) { if (!HostConfigFlags::flags.MuteHostErrorMsgIsEnabled && !shouldMute) { #ifdef _WIN32 DWORD lastError = GetLastError(); char16 wszBuff[MAX_URI_LENGTH]; fprintf(stderr, "Error in opening file '%s' ", filename); wszBuff[0] = 0; if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, lastError, 0, wszBuff, _countof(wszBuff), nullptr)) { fwprintf(stderr, _u(": %s"), wszBuff); } fwprintf(stderr, _u("\n")); #elif defined(_POSIX_VERSION) fprintf(stderr, "Error in opening file: "); perror(filename); #endif } IfFailGo(E_FAIL); } } if (file != NULL) { // Determine the file length, in bytes. fseek(file, 0, SEEK_END); lengthBytes = ftell(file); fseek(file, 0, SEEK_SET); } if (lengthBytes != 0) { bufferLength = lengthBytes + sizeof(BYTE); pRawBytes = (LPBYTE)malloc(bufferLength); } else { bufferLength = 1; pRawBytes = (LPBYTE)malloc(bufferLength); } if (nullptr == pRawBytes) { fwprintf(stderr, _u("out of memory")); IfFailGo(E_OUTOFMEMORY); } if (lengthBytes != 0) { if (file != NULL) { // // Read the entire content as a binary block. // size_t readBytes = fread(pRawBytes, sizeof(BYTE), lengthBytes, file); if (readBytes < lengthBytes * sizeof(BYTE)) { IfFailGo(E_FAIL); } } else // from module source register { // Q: module source is on persistent memory. Why do we use the copy instead? // A: if we use the same memory twice, ch doesn't know that during FinalizeCallback free. // the copy memory will be freed by the finalizer Assert(pRawBytesFromMap); memcpy_s(pRawBytes, bufferLength, pRawBytesFromMap, lengthBytes); } } if (pRawBytes) { pRawBytes[lengthBytes] = 0; // Null terminate it. Could be UTF16 } if (file != NULL) { // // Read encoding to make sure it's supported // // Warning: The UNICODE buffer for parsing is supposed to be provided by the host. // This is not a complete read of the encoding. Some encodings like UTF7, UTF1, EBCDIC, SCSU, BOCU could be // wrongly classified as ANSI // #pragma warning(push) // suppressing prefast warning that "readable size is bufferLength // bytes but 2 may be read" as bufferLength is clearly > 2 in the code that follows #pragma warning(disable:6385) C_ASSERT(sizeof(WCHAR) == 2); if (bufferLength > 2) { __analysis_assume(bufferLength > 2); #pragma prefast(push) #pragma prefast(disable:6385, "PREfast incorrectly reports this as an out-of-bound access."); if ((pRawBytes[0] == 0xFE && pRawBytes[1] == 0xFF) || (pRawBytes[0] == 0xFF && pRawBytes[1] == 0xFE) || (bufferLength > 4 && pRawBytes[0] == 0x00 && pRawBytes[1] == 0x00 && ((pRawBytes[2] == 0xFE && pRawBytes[3] == 0xFF) || (pRawBytes[2] == 0xFF && pRawBytes[3] == 0xFE)))) { // unicode unsupported fwprintf(stderr, _u("unsupported file encoding. Only ANSI and UTF8 supported")); IfFailGo(E_UNEXPECTED); } #pragma prefast(pop) } #pragma warning(pop) } contents = reinterpret_cast<LPCSTR>(pRawBytes); Error: if (SUCCEEDED(hr)) { if (lengthBytesOut) { *lengthBytesOut = lengthBytes; } } if (file != NULL) { fclose(file); } if (pRawBytes && reinterpret_cast<LPCSTR>(pRawBytes) != contents) { free(pRawBytes); } return hr; }
//***************************************************************************** // Get info about the MD stream. // Low level access to stream data. Intended for metainfo, and such. //***************************************************************************** __checkReturn STDMETHODIMP CLiteWeightStgdbRW::GetRawStreamInfo( ULONG ix, // [IN] Stream ordinal desired. const char **ppchName, // [OUT] put pointer to stream name here. const void **ppv, // [OUT] put pointer to MD stream here. ULONG *pcb) // [OUT] put size of the stream here. { HRESULT hr = NOERROR; STORAGEHEADER sHdr; // Header for the storage. PSTORAGESTREAM pStream; // Pointer to each stream. ULONG i; // Loop control. void *pData; ULONG cbData; #ifdef FEATURE_METADATA_CUSTOM_DATA_SOURCE if (m_pStgIO == NULL) IfFailGo(COR_E_NOTSUPPORTED); #endif pData = m_pStgIO->m_pData; cbData = m_pStgIO->m_cbData; // Validate the signature of the format, or it isn't ours. IfFailGo(MDFormat::VerifySignature((PSTORAGESIGNATURE) pData, cbData)); // Get back the first stream. pStream = MDFormat::GetFirstStream(&sHdr, pData); if (pStream == NULL) { Debug_ReportError("Invalid MetaData storage signature - cannot get the first stream header."); IfFailGo(CLDB_E_FILE_CORRUPT); } // Check that the requested stream exists. if (ix >= sHdr.GetiStreams()) return S_FALSE; // Skip to the desired stream. for (i = 0; i < ix; i++) { PSTORAGESTREAM pNext = pStream->NextStream(); // Check that stream header is within the buffer. if (((LPBYTE)pStream >= ((LPBYTE)pData + cbData)) || ((LPBYTE)pNext > ((LPBYTE)pData + cbData))) { Debug_ReportError("Stream header is not within MetaData block."); hr = CLDB_E_FILE_CORRUPT; goto ErrExit; } // Check that the stream data starts and fits within the buffer. // need two checks on size because of wraparound. if ((pStream->GetOffset() > cbData) || (pStream->GetSize() > cbData) || ((pStream->GetSize() + pStream->GetOffset()) > cbData)) { Debug_ReportError("Stream data are not within MetaData block."); hr = CLDB_E_FILE_CORRUPT; goto ErrExit; } // Pick off the next stream if there is one. pStream = pNext; } if (pStream != NULL) { *ppv = (const void *)((const BYTE *)pData + pStream->GetOffset()); *pcb = pStream->GetSize(); *ppchName = pStream->GetName(); } else { *ppv = NULL; *pcb = 0; *ppchName = NULL; // Invalid input to the method hr = CLDB_E_FILE_CORRUPT; } ErrExit: return hr; } // CLiteWeightStgdbRW::GetRawStreamInfo
//***************************************************************************** // Driver for the delta process. //***************************************************************************** __checkReturn HRESULT CMiniMdRW::ApplyDelta( CMiniMdRW &mdDelta) // Interface to MD with the ENC delta. { HRESULT hr = S_OK; ULONG iENC; // Loop control. ULONG iRid; // RID of some record. ULONG iNew; // RID of a new record. int i; // Loop control. ULONG ixTbl; // A table. #ifdef _DEBUG if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_ApplyDeltaBreak)) { _ASSERTE(!"CMiniMDRW::ApplyDelta()"); } #endif // _DEBUG // Init the suppressed column table. We know this one isn't zero... if (m_SuppressedDeltaColumns[TBL_TypeDef] == 0) { m_SuppressedDeltaColumns[TBL_EventMap] = (1 << EventMapRec::COL_EventList); m_SuppressedDeltaColumns[TBL_PropertyMap] = (1 << PropertyMapRec::COL_PropertyList); m_SuppressedDeltaColumns[TBL_EventMap] = (1 << EventMapRec::COL_EventList); m_SuppressedDeltaColumns[TBL_Method] = (1 << MethodRec::COL_ParamList); m_SuppressedDeltaColumns[TBL_TypeDef] = (1 << TypeDefRec::COL_FieldList)|(1<<TypeDefRec::COL_MethodList); } // Verify the version of the MD. if (m_Schema.m_major != mdDelta.m_Schema.m_major || m_Schema.m_minor != mdDelta.m_Schema.m_minor) { _ASSERTE(!"Version of Delta MetaData is a incompatible with current MetaData."); //<TODO>@FUTURE: unique error in the future since we are not shipping ENC.</TODO> return E_INVALIDARG; } // verify MVIDs. ModuleRec *pModDelta; ModuleRec *pModBase; IfFailGo(mdDelta.GetModuleRecord(1, &pModDelta)); IfFailGo(GetModuleRecord(1, &pModBase)); GUID GuidDelta; GUID GuidBase; IfFailGo(mdDelta.getMvidOfModule(pModDelta, &GuidDelta)); IfFailGo(getMvidOfModule(pModBase, &GuidBase)); if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_DeltaCheck) && (GuidDelta != GuidBase)) { _ASSERTE(!"Delta MetaData has different base than current MetaData."); return E_INVALIDARG; } #ifndef FEATURE_CORECLR // Verify that the delta is based on the base. IfFailGo(mdDelta.getEncBaseIdOfModule(pModDelta, &GuidDelta)); IfFailGo(getEncBaseIdOfModule(pModBase,&GuidBase)); if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_DeltaCheck) && CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_UseMinimalDeltas) && (GuidDelta != GuidBase)) { _ASSERTE(!"The Delta MetaData is based on a different generation than the current MetaData."); return E_INVALIDARG; } #endif //!FEATURE_CORECLR // Let the other md prepare for sparse records. IfFailGo(mdDelta.StartENCMap()); // Fix the heaps. IfFailGo(ApplyHeapDeltas(mdDelta)); // Truncate some tables in preparation to copy in new ENCLog data. for (i = 0; (ixTbl = m_TruncatedEncTables[i]) != (ULONG)-1; ++i) { m_Tables[ixTbl].Delete(); IfFailGo(m_Tables[ixTbl].InitializeEmpty_WithRecordCount( m_TableDefs[ixTbl].m_cbRec, mdDelta.m_Schema.m_cRecs[ixTbl] COMMA_INDEBUG_MD(TRUE))); // fIsReadWrite INDEBUG_MD(m_Tables[ixTbl].Debug_SetTableInfo(NULL, ixTbl)); m_Schema.m_cRecs[ixTbl] = 0; } // For each record in the ENC log... for (iENC = 1; iENC <= mdDelta.m_Schema.m_cRecs[TBL_ENCLog]; ++iENC) { // Get the record, and the updated token. ENCLogRec *pENC; IfFailGo(mdDelta.GetENCLogRecord(iENC, &pENC)); ENCLogRec *pENC2; IfFailGo(AddENCLogRecord(&pENC2, &iNew)); IfNullGo(pENC2); ENCLogRec *pENC3; _ASSERTE(iNew == iENC); ULONG func = pENC->GetFuncCode(); pENC2->SetFuncCode(pENC->GetFuncCode()); pENC2->SetToken(pENC->GetToken()); // What kind of record is this? if (IsRecId(pENC->GetToken())) { // Non-token table iRid = RidFromRecId(pENC->GetToken()); ixTbl = TblFromRecId(pENC->GetToken()); } else { // Token table. iRid = RidFromToken(pENC->GetToken()); ixTbl = GetTableForToken(pENC->GetToken()); } RID rid_Ignore; // Switch based on the function code. switch (func) { case eDeltaMethodCreate: // Next ENC record will define the new Method. MethodRec *pMethodRecord; IfFailGo(AddMethodRecord(&pMethodRecord, &rid_Ignore)); IfFailGo(AddMethodToTypeDef(iRid, m_Schema.m_cRecs[TBL_Method])); break; case eDeltaParamCreate: // Next ENC record will define the new Param. This record is // tricky because params will be re-ordered based on their sequence, // but the sequence isn't set until the NEXT record is applied. // So, for ParamCreate only, apply the param record delta before // adding the parent-child linkage. ParamRec *pParamRecord; IfFailGo(AddParamRecord(&pParamRecord, &rid_Ignore)); // Should have recorded a Param delta after the Param add. _ASSERTE(iENC<mdDelta.m_Schema.m_cRecs[TBL_ENCLog]); IfFailGo(mdDelta.GetENCLogRecord(iENC+1, &pENC3)); _ASSERTE(pENC3->GetFuncCode() == 0); _ASSERTE(GetTableForToken(pENC3->GetToken()) == TBL_Param); IfFailGo(ApplyTableDelta(mdDelta, TBL_Param, RidFromToken(pENC3->GetToken()), eDeltaFuncDefault)); // Now that Param record is OK, set up linkage. IfFailGo(AddParamToMethod(iRid, m_Schema.m_cRecs[TBL_Param])); break; case eDeltaFieldCreate: // Next ENC record will define the new Field. FieldRec *pFieldRecord; IfFailGo(AddFieldRecord(&pFieldRecord, &rid_Ignore)); IfFailGo(AddFieldToTypeDef(iRid, m_Schema.m_cRecs[TBL_Field])); break; case eDeltaPropertyCreate: // Next ENC record will define the new Property. PropertyRec *pPropertyRecord; IfFailGo(AddPropertyRecord(&pPropertyRecord, &rid_Ignore)); IfFailGo(AddPropertyToPropertyMap(iRid, m_Schema.m_cRecs[TBL_Property])); break; case eDeltaEventCreate: // Next ENC record will define the new Event. EventRec *pEventRecord; IfFailGo(AddEventRecord(&pEventRecord, &rid_Ignore)); IfFailGo(AddEventToEventMap(iRid, m_Schema.m_cRecs[TBL_Event])); break; case eDeltaFuncDefault: IfFailGo(ApplyTableDelta(mdDelta, ixTbl, iRid, func)); break; default: _ASSERTE(!"Unexpected function in ApplyDelta"); IfFailGo(E_UNEXPECTED); break; } } m_Schema.m_cRecs[TBL_ENCLog] = mdDelta.m_Schema.m_cRecs[TBL_ENCLog]; ErrExit: // Store the result for returning (IfFailRet will modify hr) HRESULT hrReturn = hr; IfFailRet(mdDelta.EndENCMap()); #ifndef FEATURE_CORECLR if (SUCCEEDED(hrReturn) && CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_DeltaCheck) && CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_UseMinimalDeltas)) { GUID GuidNewBase; // We'll use the delta's 'delta guid' for our new base guid IfFailRet(mdDelta.getEncIdOfModule(pModDelta, &GuidNewBase)); IfFailRet(PutGuid(TBL_Module, ModuleRec::COL_EncBaseId, pModBase, GuidNewBase)); } #endif //!FEATURE_CORECLR return hrReturn; } // CMiniMdRW::ApplyDelta
//***************************************************************************** // Given an StgIO, opens compressed streams and do proper initialization. // This is a helper for other Init functions. //***************************************************************************** __checkReturn HRESULT CLiteWeightStgdbRW::InitFileForRead( StgIO * pStgIO, // For file i/o. int bReadOnly) // If read-only open. { TiggerStorage * pStorage = NULL; void * pvData; ULONG cbData; HRESULT hr = NOERROR; // Allocate a new storage object which has IStorage on it. pStorage = new (nothrow) TiggerStorage(); IfNullGo(pStorage); // Init the storage object on the backing storage. OptionValue ov; IfFailGo(m_MiniMd.GetOption(&ov)); IfFailGo(pStorage->Init(pStgIO, ov.m_RuntimeVersion)); // Save pointers to header structure for version string. _ASSERTE((m_pvMd == NULL) && (m_cbMd == 0)); IfFailGo(pStorage->GetHeaderPointer(&m_pvMd, &m_cbMd)); // Check to see if this is a minimal metadata if (SUCCEEDED(pStorage->OpenStream(MINIMAL_MD_STREAM, &cbData, &pvData))) { m_MiniMd.m_fMinimalDelta = TRUE; } // Load the string pool. if (SUCCEEDED(hr = pStorage->OpenStream(STRING_POOL_STREAM, &cbData, &pvData))) { // String pool has to end with a null-terminator, therefore we don't have to check string pool // content on access. // Shrink size of the pool to the last null-terminator found. while (cbData != 0) { if (((LPBYTE)pvData)[cbData - 1] == 0) { // We have found last null terminator break; } // Shrink size of the pool cbData--; Debug_ReportError("String heap/pool does not end with null-terminator ... shrinking the heap."); } IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolStrings, pvData, cbData, bReadOnly)); } else { if (hr != STG_E_FILENOTFOUND) { IfFailGo(hr); } IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolStrings, NULL, 0, bReadOnly)); } // Load the user string blob pool. if (SUCCEEDED(hr = pStorage->OpenStream(US_BLOB_POOL_STREAM, &cbData, &pvData))) { IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolUSBlobs, pvData, cbData, bReadOnly)); } else { if (hr != STG_E_FILENOTFOUND) { IfFailGo(hr); } IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolUSBlobs, NULL, 0, bReadOnly)); } // Load the guid pool. if (SUCCEEDED(hr = pStorage->OpenStream(GUID_POOL_STREAM, &cbData, &pvData))) { IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolGuids, pvData, cbData, bReadOnly)); } else { if (hr != STG_E_FILENOTFOUND) { IfFailGo(hr); } IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolGuids, NULL, 0, bReadOnly)); } // Load the blob pool. if (SUCCEEDED(hr = pStorage->OpenStream(BLOB_POOL_STREAM, &cbData, &pvData))) { IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolBlobs, pvData, cbData, bReadOnly)); } else { if (hr != STG_E_FILENOTFOUND) { IfFailGo(hr); } IfFailGo(m_MiniMd.InitPoolOnMem(MDPoolBlobs, NULL, 0, bReadOnly)); } // Open the metadata. hr = pStorage->OpenStream(COMPRESSED_MODEL_STREAM, &cbData, &pvData); if (hr == STG_E_FILENOTFOUND) { IfFailGo(pStorage->OpenStream(ENC_MODEL_STREAM, &cbData, &pvData)); } IfFailGo(m_MiniMd.InitOnMem(pvData, cbData, bReadOnly)); IfFailGo(m_MiniMd.PostInit(0)); ErrExit: if (pStorage != NULL) { delete pStorage; } return hr; } // CLiteWeightStgdbRW::InitFileForRead
//***************************************************************************** // CheckFileFormat // This function will determine if the in-memory image is a readonly, readwrite, // or ICR format. //***************************************************************************** HRESULT CheckFileFormat( LPVOID pData, ULONG cbData, MDFileFormat *pFormat) // [OUT] the file format { HRESULT hr = NOERROR; STORAGEHEADER sHdr; // Header for the storage. PSTORAGESTREAM pStream; // Pointer to each stream. int i; ULONG cbStreamBuffer; _ASSERTE(pFormat != NULL); *pFormat = MDFormat_Invalid; // Validate the signature of the format, or it isn't ours. if (FAILED(hr = MDFormat::VerifySignature((PSTORAGESIGNATURE) pData, cbData))) goto ErrExit; // Remaining buffer size behind the stream header (pStream). cbStreamBuffer = cbData; // Get back the first stream. pStream = MDFormat::GetFirstStream_Verify(&sHdr, pData, &cbStreamBuffer); if (pStream == NULL) { Debug_ReportError("Invalid MetaData storage signature - cannot get the first stream header."); IfFailGo(CLDB_E_FILE_CORRUPT); } // Loop through each stream and pick off the ones we need. for (i = 0; i < sHdr.GetiStreams(); i++) { // Do we have enough buffer to read stream header? if (cbStreamBuffer < sizeof(*pStream)) { Debug_ReportError("Stream header is not within MetaData block."); IfFailGo(CLDB_E_FILE_CORRUPT); } // Get next stream. PSTORAGESTREAM pNext = pStream->NextStream_Verify(); // Check that stream header is within the buffer. if (((LPBYTE)pStream >= ((LPBYTE)pData + cbData)) || ((LPBYTE)pNext > ((LPBYTE)pData + cbData))) { Debug_ReportError("Stream header is not within MetaData block."); hr = CLDB_E_FILE_CORRUPT; goto ErrExit; } // Check that the stream data starts and fits within the buffer. // need two checks on size because of wraparound. if ((pStream->GetOffset() > cbData) || (pStream->GetSize() > cbData) || ((pStream->GetSize() + pStream->GetOffset()) < pStream->GetOffset()) || ((pStream->GetSize() + pStream->GetOffset()) > cbData)) { Debug_ReportError("Stream data are not within MetaData block."); hr = CLDB_E_FILE_CORRUPT; goto ErrExit; } // Pick off the location and size of the data. if (strcmp(pStream->GetName(), COMPRESSED_MODEL_STREAM_A) == 0) { // Validate that only one of compressed/uncompressed is present. if (*pFormat != MDFormat_Invalid) { // Already found a good stream. Debug_ReportError("Compressed model stream #~ is second important stream."); hr = CLDB_E_FILE_CORRUPT; goto ErrExit; } // Found the compressed meta data stream. *pFormat = MDFormat_ReadOnly; } else if (strcmp(pStream->GetName(), ENC_MODEL_STREAM_A) == 0) { // Validate that only one of compressed/uncompressed is present. if (*pFormat != MDFormat_Invalid) { // Already found a good stream. Debug_ReportError("ENC model stream #- is second important stream."); hr = CLDB_E_FILE_CORRUPT; goto ErrExit; } // Found the ENC meta data stream. *pFormat = MDFormat_ReadWrite; } else if (strcmp(pStream->GetName(), SCHEMA_STREAM_A) == 0) { // Found the uncompressed format *pFormat = MDFormat_ICR; // keep going. We may find the compressed format later. // If so, we want to use the compressed format. } // Pick off the next stream if there is one. pStream = pNext; cbStreamBuffer = (ULONG)((LPBYTE)pData + cbData - (LPBYTE)pNext); } if (*pFormat == MDFormat_Invalid) { // Didn't find a good stream. Debug_ReportError("Cannot find MetaData stream."); hr = CLDB_E_FILE_CORRUPT; } ErrExit: return hr; } // CheckFileFormat
//***************************************************************************** // Open a metadata section for read //***************************************************************************** __checkReturn HRESULT CLiteWeightStgdbRW::OpenForRead( LPCWSTR szDatabase, // Name of database. void *pbData, // Data to open on top of, 0 default. ULONG cbData, // How big is the data. DWORD dwFlags) // Flags for the open. { LPCWSTR pNoFile=W(""); // Constant for empty file name. StgIO *pStgIO = NULL; // For file i/o. HRESULT hr; m_pImage = NULL; m_dwImageSize = 0; m_eFileType = FILETYPE_UNKNOWN; // szDatabase, and pbData are mutually exclusive. Only one may be // non-NULL. Having both NULL means empty stream creation. // _ASSERTE(!(szDatabase && (pbData))); _ASSERTE(!(pbData && (szDatabase))); // Open on memory needs there to be something to work with. if (pbData && cbData == 0) IfFailGo(CLDB_E_NO_DATA); // Make sure we have a path to work with. if (!szDatabase) szDatabase = pNoFile; // Sanity check the name lentgh. if (!IsValidFileNameLength(szDatabase)) { IfFailGo(E_INVALIDARG); } // If we have storage to work with, init it and get type. if (*szDatabase || pbData) { // Allocate a storage instance to use for i/o. if ((pStgIO = new (nothrow) StgIO) == 0) IfFailGo( E_OUTOFMEMORY ); DBPROPMODE dmOpenFlags = DBPROP_TMODEF_READ; // If we're taking ownership of this memory..... if (IsOfTakeOwnership(dwFlags)) { #ifdef FEATURE_METADATA_STANDALONE_WINRT_RO // Shared memory uses ole32.dll - we cannot depend on it in the standalone WinRT Read-Only DLL IfFailGo(E_INVALIDARG); #else dmOpenFlags = (DBPROPMODE)(dmOpenFlags | DBPROP_TMODEF_SHAREDMEM); #endif //!FEATURE_METADATA_STANDALONE_WINRT_RO } #ifdef FEATURE_METADATA_LOAD_TRUSTED_IMAGES if (IsOfTrustedImage(dwFlags)) dmOpenFlags = (DBPROPMODE)(dmOpenFlags | DBPROP_TMODEF_TRYLOADLIBRARY); #endif // Open the storage so we can read the signature if there is already data. IfFailGo( pStgIO->Open(szDatabase, dmOpenFlags, pbData, cbData, 0, // IStream* NULL) ); // Determine the type of file we are working with. IfFailGo( _GetFileTypeForPath(pStgIO, &m_eFileType) ); } // Check for default type. if (m_eFileType == FILETYPE_CLB) { // If user wanted us to make a local copy of the data, do that now. if (IsOfCopyMemory(dwFlags)) IfFailGo(pStgIO->LoadFileToMemory()); // Try the native .clb file. IfFailGo( InitFileForRead(pStgIO, IsOfRead(dwFlags)) ); } // PE/COFF executable/object format. This requires us to find the .clb // inside the binary before doing the Init. else if (m_eFileType == FILETYPE_NTPE || m_eFileType == FILETYPE_NTOBJ) { //<TODO>@FUTURE: Ideally the FindImageMetaData function //@FUTURE: would take the pStgIO and map only the part of the file where //@FUTURE: our data lives, leaving the rest alone. This would be smaller //@FUTURE: working set for us.</TODO> void *ptr; ULONG cbSize; // Map the entire binary for the FindImageMetaData function. IfFailGo( pStgIO->MapFileToMem(ptr, &cbSize) ); // Find the .clb inside of the content. if (m_eFileType == FILETYPE_NTPE) { m_pImage = ptr; m_dwImageSize = cbSize; hr = FindImageMetaData(ptr, cbSize, pStgIO->GetMemoryMappedType() == MTYPE_IMAGE, &ptr, &cbSize); } else { _ASSERTE(pStgIO->GetMemoryMappedType() != MTYPE_IMAGE); hr = FindObjMetaData(ptr, cbSize, &ptr, &cbSize); } // Was the metadata found inside the PE file? if (FAILED(hr)) { if (hr == E_OUTOFMEMORY) IfFailGo(E_OUTOFMEMORY); // No clb in the PE, assume it is a type library. m_eFileType = FILETYPE_TLB; // Let the caller deal with a TypeLib. IfFailGo(hr); } else { // Metadata was found inside the file. // Now reset the base of the stg object so that all memory accesses // are relative to the .clb content. // IfFailGo( pStgIO->SetBaseRange(ptr, cbSize) ); // If user wanted us to make a local copy of the data, do that now. if (IsOfCopyMemory(dwFlags)) { // Cache the PEKind, Machine. GetPEKind(pStgIO->GetMemoryMappedType(), NULL, NULL); // Copy the file into memory; releases the file. IfFailGo(pStgIO->LoadFileToMemory()); // No longer have the image. m_pImage = NULL; m_dwImageSize = 0; } // Defer to the normal lookup. IfFailGo( InitFileForRead(pStgIO, IsOfRead(dwFlags)) ); } } else if (m_eFileType == FILETYPE_TLB) { // Let the caller deal with a TypeLib. IfFailGo(CLDB_E_NO_DATA); } // This spells trouble, we need to handle all types we might find. else { _ASSERTE(!"Unknown file type."); IfFailGo( E_FAIL ); } // Save off everything. IfFailGo(SetFileName(szDatabase)); // If this was a file... if (pbData == NULL) { WIN32_FILE_ATTRIBUTE_DATA faData; if (!WszGetFileAttributesEx(szDatabase, GetFileExInfoStandard, &faData)) IfFailGo(E_FAIL); m_dwDatabaseLFS = faData.nFileSizeLow; m_dwDatabaseLFT = faData.ftLastWriteTime.dwLowDateTime; } ErrExit: if (SUCCEEDED(hr)) { m_pStgIO = pStgIO; } else { if (pStgIO != NULL) pStgIO->Release(); } return hr; }
int _tmain(int argc, _TCHAR* argv[]) { HRESULT hr = S_OK; SolidEdgeFramework::ApplicationPtr pApplication = NULL; SolidEdgeAssembly::AssemblyDocumentPtr pAssemblyDocument = NULL; SolidEdgeAssembly::ConfigurationsPtr pConfigurations = NULL; SolidEdgeAssembly::ConfigurationPtr pConfiguration = NULL; CString strConfigName; // Initialize COM. ::CoInitialize(NULL); // Attempt to connect to a running instance of Solid Edge. IfFailGo(pApplication.GetActiveObject(L"SolidEdge.Application")); // Get a reference to the active assembly document. pAssemblyDocument = pApplication->ActiveDocument; if (pAssemblyDocument != NULL) { // Get a reference to the Configurations collection. pConfigurations = pAssemblyDocument->Configurations; LONG c = pConfigurations->Count; if (pConfigurations->Count > 0) { // Get a reference tot he Configurations collection. pConfiguration = pConfigurations->Item((LONG)1); // Configuration name has to be unique so for demonstration // purposes, use a random number. strConfigName.Format(L"%s %d", L"Configuration", rand()); /* NOTE - Example is not working. Need help :-( */ SAFEARRAY* sa; SAFEARRAYBOUND aDim; aDim.lLbound = 0; aDim.cElements = 1; sa = SafeArrayCreate(VT_BSTR, 1, &aDim); long index = 0; hr = SafeArrayPutElement(sa, &index, (void*)strConfigName.AllocSysString()); VARIANT vConfigList; VariantInit(&vConfigList); vConfigList.vt = VT_ARRAY | VT_BSTR; vConfigList.parray = sa; pConfigurations->AddDerivedConfig(1, 0, 0, &vConfigList, NULL, NULL, strConfigName.AllocSysString()); SafeArrayDestroy(sa); } } else { wprintf(L"No active document.\n"); } Error: pAssemblyDocument = NULL; pApplication = NULL; // Uninitialize COM. ::CoUninitialize(); return 0; }
//***************************************************************************** // Remove a RegMeta pointer from the loaded module list //***************************************************************************** BOOL LOADEDMODULES::RemoveModuleFromLoadedList(RegMeta * pRegMeta) { BOOL bRemoved = FALSE; // Was this module removed from the cache? int iFound = -1; // Index at which it was found. ULONG cRef; // Ref count of the module. // Lock the cache for write, so that no other thread will find what this // thread is about to delete, and so that no other thread will delete // what this thread is about to try to find. HRESULT hr = S_OK; IfFailGo(InitializeStatics()); { LOCKWRITE(); // Search for this module in list of loaded modules. int count = s_pLoadedModules->Count(); for (int index = 0; index < count; index++) { if ((*s_pLoadedModules)[index] == pRegMeta) { // found a match to remove iFound = index; break; } } // If the module is still in the cache, it hasn't been deleted yet. if (iFound >= 0) { // See if there are any external references left. cRef = pRegMeta->GetRefCount(); // If the cRef that we got from the module is zero, it will stay that way, // because no other thread can discover the module while this thread holds // the lock. // OTOH, if the cRef is not zero, this thread can just return, because the // other thread will eventually take the ref count to zero, and will then // come through here to clean up the module. And this thread must not // delete the module out from under other threads. // It is possible that the cRef is zero, yet another thread has a pointer that // it discovered before this thread took the lock. (And that thread has // released the ref-counts.) In such a case, this thread can still remove the // module from the cache, and tell the caller to delete it, because the // other thread will wait on the lock, then discover that the module // is not in the cache, and it won't try to delete the module. if (cRef != 0) { // Some other thread snuck in and found the entry in the cache. return FALSE; } // No other thread owns the object. Remove from cache, and tell caller // that we're done with it. (Caller will delete.) s_pLoadedModules->Delete(iFound); bRemoved = TRUE; // If the module is read-only, remove from hash. if (pRegMeta->IsReadOnly()) { // There may have been multiple capitalizations pointing to the same entry. // Find and remove all of them. for (ULONG ixHash = 0; ixHash < LOADEDMODULES_HASH_SIZE; ++ixHash) { if (m_HashedModules[ixHash] == pRegMeta) m_HashedModules[ixHash] = NULL; } } } } ErrExit: return bRemoved; } // LOADEDMODULES::RemoveModuleFromLoadedList