// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. // TODO: Re-implement with MC++ if we ever compile any mscorlib code with that #include "common.h" #include "mlinfo.h" #include "managedmdimport.hpp" #include "wrappers.h" void ThrowMetaDataImportException(HRESULT hr) { WRAPPER_NO_CONTRACT; if (hr == CLDB_E_RECORD_NOTFOUND) return; MethodDescCallSite throwError(METHOD__METADATA_IMPORT__THROW_ERROR); ARG_SLOT args[] = { hr }; throwError.Call(args); } // // MetaDataImport // extern BOOL ParseNativeTypeInfo(NativeTypeParamInfo* pInfo, PCCOR_SIGNATURE pvNativeType, ULONG cbNativeType); FCIMPL11(void, MetaDataImport::GetMarshalAs, BYTE* pvNativeType, ULONG cbNativeType, INT32* unmanagedType, INT32* safeArraySubType, STRINGREF* safeArrayUserDefinedSubType, INT32* arraySubType, INT32* sizeParamIndex, INT32* sizeConst, STRINGREF* marshalType, STRINGREF* marshalCookie, INT32* iidParamIndex) { FCALL_CONTRACT; HELPER_METHOD_FRAME_BEGIN_0(); { NativeTypeParamInfo info; ZeroMemory(&info, sizeof(NativeTypeParamInfo)); if (!ParseNativeTypeInfo(&info, pvNativeType, cbNativeType)) { ThrowMetaDataImportException(E_FAIL); } *unmanagedType = info.m_NativeType; *sizeParamIndex = info.m_CountParamIdx; *sizeConst = info.m_Additive; *arraySubType = info.m_ArrayElementType; #ifdef FEATURE_COMINTEROP *iidParamIndex = info.m_IidParamIndex; *safeArraySubType = info.m_SafeArrayElementVT; *safeArrayUserDefinedSubType = info.m_strSafeArrayUserDefTypeName == NULL ? NULL : StringObject::NewString(info.m_strSafeArrayUserDefTypeName, info.m_cSafeArrayUserDefTypeNameBytes); #else *iidParamIndex = 0; *safeArraySubType = VT_EMPTY; *safeArrayUserDefinedSubType = NULL; #endif *marshalType = info.m_strCMMarshalerTypeName == NULL ? NULL : StringObject::NewString(info.m_strCMMarshalerTypeName, info.m_cCMMarshalerTypeNameBytes); *marshalCookie = info.m_strCMCookie == NULL ? NULL : StringObject::NewString(info.m_strCMCookie, info.m_cCMCookieStrBytes); } HELPER_METHOD_FRAME_END(); } FCIMPLEND MDImpl4(Object *, MetaDataImport::GetDefaultValue, mdToken tk, INT64* pDefaultValue, INT32* pLength, INT32* pCorElementType) { FCALL_CONTRACT; HRESULT hr = S_OK; Object *pRetVal = NULL; BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), FCThrow(kStackOverflowException)); IMDInternalImport *_pScope = pScope; MDDefaultValue value; IfFailGo(_pScope->GetDefaultValue(tk, &value)); // We treat string values differently. That's because on big-endian architectures we can't return a // pointer to static string data in the metadata, we have to buffer the string in order to byte-swap // all the unicode characters. MDDefaultValue therefore has a destructor on big-endian machines which // reclaims this buffer, implying we can't safely return the embedded pointer to managed code. // The easiest thing for us to do is to construct the managed string object here, in the context of // the still valid MDDefaultValue. We can't return a managed object via the normal out parameter // because it won't be GC protected, so in this special case null the output parameter and return // the string via the protected return result (which is null for all other cases). if (value.m_bType == ELEMENT_TYPE_STRING) { HELPER_METHOD_FRAME_BEGIN_RET_0(); *pDefaultValue = 0; STRINGREF refRetval = StringObject::NewString(value.m_wzValue, value.m_cbSize / sizeof(WCHAR)); pRetVal = STRINGREFToObject(refRetval); HELPER_METHOD_FRAME_END(); } else { *pDefaultValue = value.m_ullValue; } *pCorElementType = (UINT32)value.m_bType; *pLength = (INT32)value.m_cbSize; ErrExit: END_SO_INTOLERANT_CODE; if (FAILED(hr)) { fprintf(stderr, "@@[SR] %s:%d, exception number(%ld)\n", __FILE__, __LINE__, hr); FCThrow(kBadImageFormatException); } return pRetVal; } FCIMPLEND MDImpl3(void, MetaDataImport::GetCustomAttributeProps, mdCustomAttribute cv, mdToken* ptkType, ConstArray* ppBlob) { FCALL_CONTRACT; HRESULT hr = S_OK; IMDInternalImport *_pScope = pScope; BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), FCThrowVoid(kStackOverflowException)); IfFailGo(_pScope->GetCustomAttributeProps(cv, ptkType)); IfFailGo(_pScope->GetCustomAttributeAsBlob(cv, (const void **)&ppBlob->m_array, (ULONG *)&ppBlob->m_count)); ErrExit: END_SO_INTOLERANT_CODE; if (FAILED(hr)) { fprintf(stderr, "@@[SR] %s:%d, exception number(%ld)\n", __FILE__, __LINE__, hr); FCThrowVoid(kBadImageFormatException); } } FCIMPLEND static int * EnsureResultSize(MetadataEnumResult * pResult, ULONG length) { CONTRACTL { THROWS; GC_TRIGGERS; MODE_COOPERATIVE; } CONTRACTL_END; int * p; if (length >= NumItems(pResult->smallResult) || DbgRandomOnExe(.01)) { pResult->largeResult = (I4Array *)OBJECTREFToObject(AllocatePrimitiveArray(ELEMENT_TYPE_I4, length)); p = pResult->largeResult->GetDirectPointerToNonObjectElements(); } else { ZeroMemory(pResult->smallResult, sizeof(pResult->smallResult)); p = pResult->smallResult; } pResult->length = length; return p; } MDImpl3(void, MetaDataImport::Enum, mdToken type, mdToken tkParent, MetadataEnumResult * pResult) { CONTRACTL { FCALL_CHECK; PRECONDITION(pResult != NULL); } CONTRACTL_END; HELPER_METHOD_FRAME_BEGIN_0(); { IMDInternalImport *_pScope = pScope; if (type == mdtTypeDef) { ULONG nestedClassesCount; IfFailThrow(_pScope->GetCountNestedClasses(tkParent, &nestedClassesCount)); mdTypeDef* arToken = (mdTypeDef*)EnsureResultSize(pResult, nestedClassesCount); IfFailThrow(_pScope->GetNestedClasses(tkParent, arToken, nestedClassesCount, &nestedClassesCount)); } else if (type == mdtMethodDef && (TypeFromToken(tkParent) == mdtProperty || TypeFromToken(tkParent) == mdtEvent)) { HENUMInternalHolder hEnum(pScope); hEnum.EnumAssociateInit(tkParent); ULONG associatesCount = hEnum.EnumGetCount(); static_assert_no_msg(sizeof(ASSOCIATE_RECORD) == 2 * sizeof(int)); ASSOCIATE_RECORD* arAssocRecord = (ASSOCIATE_RECORD*)EnsureResultSize(pResult, 2 * associatesCount); IfFailThrow(_pScope->GetAllAssociates(&hEnum, arAssocRecord, associatesCount)); } else { HENUMInternalHolder hEnum(pScope); hEnum.EnumInit(type, tkParent); ULONG count = hEnum.EnumGetCount(); mdToken* arToken = (mdToken*)EnsureResultSize(pResult, count); for(COUNT_T i = 0; i < count && _pScope->EnumNext(&hEnum, &arToken[i]); i++); } } HELPER_METHOD_FRAME_END(); } FCIMPLEND #if defined(_MSC_VER) && defined(_TARGET_X86_) #pragma optimize("y", on) // Small critical routines, don't put in EBP frame #endif MDImpl1(FC_BOOL_RET, MetaDataImport::IsValidToken, mdToken tk) { FCALL_CONTRACT; IMDInternalImport *_pScope = pScope; FC_RETURN_BOOL(_pScope->IsValidToken(tk)); } FCIMPLEND MDImpl3(void, MetaDataImport::GetClassLayout, mdTypeDef td, DWORD* pdwPackSize, ULONG* pulClassSize) { FCALL_CONTRACT; HRESULT hr = S_OK; BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), FCThrowVoid(kStackOverflowException)); { IMDInternalImport *_pScope = pScope; if (pdwPackSize != NULL) { hr = _pScope->GetClassPackSize(td, (ULONG *)pdwPackSize); if (hr == CLDB_E_RECORD_NOTFOUND) { *pdwPackSize = 0; hr = S_OK; } IfFailGo(hr); } if (pulClassSize != NULL) { hr = _pScope->GetClassTotalSize(td, pulClassSize); if (hr == CLDB_E_RECORD_NOTFOUND) { *pulClassSize = 0; hr = S_OK; } IfFailGo(hr); } } ErrExit: END_SO_INTOLERANT_CODE; if (FAILED(hr)) { fprintf(stderr, "@@[SR] %s:%d, exception number(%ld)\n", __FILE__, __LINE__, hr); FCThrowVoid(kBadImageFormatException); } } FCIMPLEND MDImpl3(FC_BOOL_RET, MetaDataImport::GetFieldOffset, mdTypeDef td, mdFieldDef target, DWORD* pdwFieldOffset) { FCALL_CONTRACT; HRESULT hr = S_OK; IMDInternalImport *_pScope = pScope; MD_CLASS_LAYOUT layout; BOOL retVal = FALSE; BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), FCThrow(kStackOverflowException)); IfFailGo(_pScope->GetClassLayoutInit(td, &layout)); ULONG cFieldOffset; cFieldOffset = layout.m_ridFieldEnd - layout.m_ridFieldCur; for (COUNT_T i = 0; i < cFieldOffset; i ++) { mdFieldDef fd; ULONG offset; IfFailGo(_pScope->GetClassLayoutNext(&layout, &fd, &offset)); if (fd == target) { *pdwFieldOffset = offset; retVal = TRUE; break; } } ErrExit: END_SO_INTOLERANT_CODE; if (FAILED(hr)) { fprintf(stderr, "@@[SR] %s:%d, exception number(%ld)\n", __FILE__, __LINE__, hr); FCThrow(kBadImageFormatException); } FC_RETURN_BOOL(retVal); } FCIMPLEND MDImpl3(void, MetaDataImport::GetUserString, mdToken tk, LPCSTR* pszName, ULONG* pCount) { FCALL_CONTRACT; HRESULT hr; IMDInternalImport *_pScope = pScope; BOOL bHasExtendedChars; BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), FCThrowVoid(kStackOverflowException)); hr = _pScope->GetUserString(tk, pCount, &bHasExtendedChars, (LPCWSTR *)pszName); END_SO_INTOLERANT_CODE; if (FAILED(hr)) { fprintf(stderr, "@@[SR] %s:%d, exception number(%ld)\n", __FILE__, __LINE__, hr); FCThrowVoid(kBadImageFormatException); } } FCIMPLEND MDImpl2(void, MetaDataImport::GetName, mdToken tk, LPCSTR* pszName) { FCALL_CONTRACT; HRESULT hr = S_OK; IMDInternalImport *_pScope = pScope; BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), FCThrowVoid(kStackOverflowException)); if (TypeFromToken(tk) == mdtMethodDef) { hr = _pScope->GetNameOfMethodDef(tk, pszName); } else if (TypeFromToken(tk) == mdtParamDef) { USHORT seq; DWORD attr; hr = _pScope->GetParamDefProps(tk, &seq, &attr, pszName); } else if (TypeFromToken(tk) == mdtFieldDef) { hr = _pScope->GetNameOfFieldDef(tk, pszName); } else if (TypeFromToken(tk) == mdtProperty) { hr = _pScope->GetPropertyProps(tk, pszName, NULL, NULL, NULL); } else if (TypeFromToken(tk) == mdtEvent) { hr = _pScope->GetEventProps(tk, pszName, NULL, NULL); } else if (TypeFromToken(tk) == mdtModule) { hr = _pScope->GetModuleRefProps(tk, pszName); } else if (TypeFromToken(tk) == mdtTypeDef) { LPCSTR szNamespace = NULL; hr = _pScope->GetNameOfTypeDef(tk, pszName, &szNamespace); } else { hr = E_FAIL; } END_SO_INTOLERANT_CODE; if (FAILED(hr)) { fprintf(stderr, "@@[SR] %s:%d, exception number(%ld)\n", __FILE__, __LINE__, hr); FCThrowVoid(kBadImageFormatException); } } FCIMPLEND MDImpl2(void, MetaDataImport::GetNamespace, mdToken tk, LPCSTR* pszName) { FCALL_CONTRACT; HRESULT hr; IMDInternalImport *_pScope = pScope; LPCSTR szName = NULL; BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), FCThrowVoid(kStackOverflowException)); hr = _pScope->GetNameOfTypeDef(tk, &szName, pszName); END_SO_INTOLERANT_CODE; if (FAILED(hr)) { fprintf(stderr, "@@[SR] %s:%d, exception number(%ld)\n", __FILE__, __LINE__, hr); FCThrowVoid(kBadImageFormatException); } } FCIMPLEND MDImpl2(void, MetaDataImport::GetGenericParamProps, mdToken tk, DWORD* pAttributes) { FCALL_CONTRACT; HRESULT hr; IMDInternalImport *_pScope = pScope; BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), FCThrowVoid(kStackOverflowException)); hr = _pScope->GetGenericParamProps(tk, NULL, pAttributes, NULL, NULL, NULL); END_SO_INTOLERANT_CODE; if (FAILED(hr)) { fprintf(stderr, "@@[SR] %s:%d, exception number(%ld)\n", __FILE__, __LINE__, hr); FCThrowVoid(kBadImageFormatException); } } FCIMPLEND MDImpl3(void, MetaDataImport::GetEventProps, mdToken tk, LPCSTR* pszName, INT32 *pdwEventFlags) { FCALL_CONTRACT; HRESULT hr; IMDInternalImport *_pScope = pScope; BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), FCThrowVoid(kStackOverflowException)); hr = _pScope->GetEventProps(tk, pszName, (DWORD*)pdwEventFlags, NULL); END_SO_INTOLERANT_CODE; if (FAILED(hr)) { fprintf(stderr, "@@[SR] %s:%d, exception number(%ld)\n", __FILE__, __LINE__, hr); FCThrowVoid(kBadImageFormatException); } } FCIMPLEND MDImpl4(void, MetaDataImport::GetPinvokeMap, mdToken tk, DWORD* pMappingFlags, LPCSTR* pszImportName, LPCSTR* pszImportDll) { FCALL_CONTRACT; HRESULT hr; IMDInternalImport *_pScope = pScope; mdModule tkModule; BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), FCThrowVoid(kStackOverflowException)); hr = _pScope->GetPinvokeMap(tk, pMappingFlags, pszImportName, &tkModule); if (FAILED(hr)) { *pMappingFlags = 0; *pszImportName = NULL; *pszImportDll = NULL; hr = S_OK; } else { hr = _pScope->GetModuleRefProps(tkModule, pszImportDll); } END_SO_INTOLERANT_CODE; if (FAILED(hr)) { fprintf(stderr, "@@[SR] %s:%d, exception number(%ld)\n", __FILE__, __LINE__, hr); FCThrowVoid(kBadImageFormatException); } } FCIMPLEND MDImpl3(void, MetaDataImport::GetParamDefProps, mdToken tk, INT32* pSequence, INT32* pAttributes) { FCALL_CONTRACT; HRESULT hr; IMDInternalImport *_pScope = pScope; USHORT usSequence = 0; BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), FCThrowVoid(kStackOverflowException)); // Is this a valid token? if (_pScope->IsValidToken((mdParamDef)tk)) { LPCSTR szParamName; hr = _pScope->GetParamDefProps(tk, &usSequence, (DWORD *)pAttributes, &szParamName); } else { // Invalid token - throw an exception hr = COR_E_BADIMAGEFORMAT; } *pSequence = (INT32) usSequence; END_SO_INTOLERANT_CODE; if (FAILED(hr)) { fprintf(stderr, "@@[SR] %s:%d, exception number(%ld)\n", __FILE__, __LINE__, hr); FCThrowVoid(kBadImageFormatException); } } FCIMPLEND MDImpl2(void, MetaDataImport::GetFieldDefProps, mdToken tk, INT32 *pdwFieldFlags) { FCALL_CONTRACT; HRESULT hr; IMDInternalImport *_pScope = pScope; BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), FCThrowVoid(kStackOverflowException)); hr = _pScope->GetFieldDefProps(tk, (DWORD *)pdwFieldFlags); END_SO_INTOLERANT_CODE; if (FAILED(hr)) { fprintf(stderr, "@@[SR] %s:%d, exception number(%ld)\n", __FILE__, __LINE__, hr); FCThrowVoid(kBadImageFormatException); } } FCIMPLEND MDImpl4(void, MetaDataImport::GetPropertyProps, mdToken tk, LPCSTR* pszName, INT32 *pdwPropertyFlags, ConstArray* ppValue) { FCALL_CONTRACT; HRESULT hr; IMDInternalImport *_pScope = pScope; BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), FCThrowVoid(kStackOverflowException)); hr = _pScope->GetPropertyProps(tk, pszName, (DWORD*)pdwPropertyFlags, (PCCOR_SIGNATURE*)&ppValue->m_array, (ULONG*)&ppValue->m_count); END_SO_INTOLERANT_CODE; if (FAILED(hr)) { fprintf(stderr, "@@[SR] %s:%d, exception number(%ld)\n", __FILE__, __LINE__, hr); FCThrowVoid(kBadImageFormatException); } } FCIMPLEND MDImpl2(void, MetaDataImport::GetFieldMarshal, mdToken tk, ConstArray* ppValue) { FCALL_CONTRACT; HRESULT hr; IMDInternalImport *_pScope = pScope; BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), FCThrowVoid(kStackOverflowException)); hr = _pScope->GetFieldMarshal(tk, (PCCOR_SIGNATURE *)&ppValue->m_array, (ULONG *)&ppValue->m_count); if (hr == CLDB_E_RECORD_NOTFOUND) { ppValue->m_array = NULL; ppValue->m_count = 0; hr = S_OK; } END_SO_INTOLERANT_CODE; if (FAILED(hr)) { fprintf(stderr, "@@[SR] %s:%d, exception number(%ld)\n", __FILE__, __LINE__, hr); FCThrowVoid(kBadImageFormatException); } } FCIMPLEND MDImpl2(void, MetaDataImport::GetSigOfMethodDef, mdToken tk, ConstArray* ppValue) { FCALL_CONTRACT; HRESULT hr; IMDInternalImport *_pScope = pScope; BEGIN_SO_INTOLERANT_CODE(GetThread()) hr = _pScope->GetSigOfMethodDef(tk, (ULONG*)&ppValue->m_count, (PCCOR_SIGNATURE *)&ppValue->m_array); END_SO_INTOLERANT_CODE; if (FAILED(hr)) { fprintf(stderr, "@@[SR] %s:%d, exception number(%ld)\n", __FILE__, __LINE__, hr); FCThrowVoid(kBadImageFormatException); } } FCIMPLEND MDImpl2(void, MetaDataImport::GetSignatureFromToken, mdToken tk, ConstArray* ppValue) { FCALL_CONTRACT; HRESULT hr; IMDInternalImport *_pScope = pScope; BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), FCThrowVoid(kStackOverflowException)); hr = _pScope->GetSigFromToken(tk, (ULONG*)&ppValue->m_count, (PCCOR_SIGNATURE *)&(ppValue->m_array)); END_SO_INTOLERANT_CODE; if (FAILED(hr)) { fprintf(stderr, "@@[SR] %s:%d, exception number(%ld)\n", __FILE__, __LINE__, hr); FCThrowVoid(kBadImageFormatException); } } FCIMPLEND MDImpl2(void, MetaDataImport::GetSigOfFieldDef, mdToken tk, ConstArray* ppValue) { FCALL_CONTRACT; HRESULT hr; IMDInternalImport *_pScope = pScope; BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), FCThrowVoid(kStackOverflowException)); hr = _pScope->GetSigOfFieldDef(tk, (ULONG*)&ppValue->m_count, (PCCOR_SIGNATURE *)&ppValue->m_array); END_SO_INTOLERANT_CODE; if (FAILED(hr)) { fprintf(stderr, "@@[SR] %s:%d, exception number(%ld)\n", __FILE__, __LINE__, hr); FCThrowVoid(kBadImageFormatException); } } FCIMPLEND MDImpl2(void, MetaDataImport::GetParentToken, mdToken tk, mdToken* ptk) { FCALL_CONTRACT; HRESULT hr; IMDInternalImport *_pScope = pScope; BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), FCThrowVoid(kStackOverflowException)); switch (TypeFromToken(tk)) { case mdtTypeDef: hr = _pScope->GetNestedClassProps(tk, ptk); if (hr == CLDB_E_RECORD_NOTFOUND) { *ptk = mdTypeDefNil; hr = S_OK; } break; case mdtGenericParam: hr = _pScope->GetGenericParamProps(tk, NULL, NULL, ptk, NULL, NULL); break; case mdtMethodDef: case mdtMethodSpec: case mdtFieldDef: case mdtParamDef: case mdtMemberRef: case mdtCustomAttribute: case mdtEvent: case mdtProperty: hr = _pScope->GetParentToken(tk, ptk); break; default: hr = COR_E_BADIMAGEFORMAT; break; } END_SO_INTOLERANT_CODE; if (FAILED(hr)) { fprintf(stderr, "@@[SR] %s:%d, exception number(%ld)\n", __FILE__, __LINE__, hr); FCThrowVoid(kBadImageFormatException); } } FCIMPLEND MDImpl1(void, MetaDataImport::GetScopeProps, GUID* pmvid) { FCALL_CONTRACT; HRESULT hr; LPCSTR szName; BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), FCThrowVoid(kStackOverflowException)); IMDInternalImport *_pScope = pScope; hr = _pScope->GetScopeProps(&szName, pmvid); END_SO_INTOLERANT_CODE; if (FAILED(hr)) { fprintf(stderr, "@@[SR] %s:%d, exception number(%ld)\n", __FILE__, __LINE__, hr); FCThrowVoid(kBadImageFormatException); } } FCIMPLEND MDImpl2(void, MetaDataImport::GetMemberRefProps, mdMemberRef mr, ConstArray* ppvSigBlob) { FCALL_CONTRACT; HRESULT hr; IMDInternalImport *_pScope = pScope; LPCSTR szName_Ignore; BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), FCThrowVoid(kStackOverflowException)); hr = _pScope->GetNameAndSigOfMemberRef(mr, (PCCOR_SIGNATURE*)&ppvSigBlob->m_array, (ULONG*)&ppvSigBlob->m_count, &szName_Ignore); END_SO_INTOLERANT_CODE; if (FAILED(hr)) { fprintf(stderr, "@@[SR] %s:%d, exception number(%ld)\n", __FILE__, __LINE__, hr); FCThrowVoid(kBadImageFormatException); } } FCIMPLEND #if defined(_MSC_VER) && defined(_TARGET_X86_) #pragma optimize("", on) // restore command line optimization defaults #endif