| 1 | // Licensed to the .NET Foundation under one or more agreements. |
| 2 | // The .NET Foundation licenses this file to you under the MIT license. |
| 3 | // See the LICENSE file in the project root for more information. |
| 4 | // ============================================================ |
| 5 | // |
| 6 | // Assembly.cpp |
| 7 | // |
| 8 | |
| 9 | |
| 10 | // |
| 11 | // Implements the Assembly class |
| 12 | // |
| 13 | // ============================================================ |
| 14 | #include "common.h" |
| 15 | #include "clrprivbinderutil.h" |
| 16 | #include "assembly.hpp" |
| 17 | #include "utils.hpp" |
| 18 | |
| 19 | namespace BINDER_SPACE |
| 20 | { |
| 21 | namespace |
| 22 | { |
| 23 | BOOL IsPlatformArchitecture(PEKIND kArchitecture) |
| 24 | { |
| 25 | return ((kArchitecture != peMSIL) && (kArchitecture != peNone)); |
| 26 | } |
| 27 | |
| 28 | HRESULT GetAssemblyRefTokens(IMDInternalImport *pMDImport, |
| 29 | mdAssembly **ppAssemblyRefTokens, |
| 30 | DWORD *pdwCAssemblyRefTokens) |
| 31 | { |
| 32 | HRESULT hr = S_OK; |
| 33 | |
| 34 | _ASSERTE(pMDImport != NULL); |
| 35 | _ASSERTE(ppAssemblyRefTokens != NULL); |
| 36 | _ASSERTE(pdwCAssemblyRefTokens != NULL); |
| 37 | |
| 38 | mdAssembly *pAssemblyRefTokens = NULL; |
| 39 | COUNT_T assemblyRefCount; |
| 40 | |
| 41 | HENUMInternalHolder hEnumAssemblyRef(pMDImport); |
| 42 | IF_FAIL_GO(hEnumAssemblyRef.EnumInitNoThrow(mdtAssemblyRef, mdTokenNil)); |
| 43 | |
| 44 | assemblyRefCount = hEnumAssemblyRef.EnumGetCount(); |
| 45 | |
| 46 | pAssemblyRefTokens = new (nothrow) mdAssemblyRef[assemblyRefCount]; |
| 47 | if (pAssemblyRefTokens == NULL) |
| 48 | { |
| 49 | IF_FAIL_GO(E_OUTOFMEMORY); |
| 50 | } |
| 51 | ZeroMemory(pAssemblyRefTokens, assemblyRefCount * sizeof(mdAssemblyRef)); |
| 52 | |
| 53 | for (COUNT_T i = 0; i < assemblyRefCount; i++) |
| 54 | { |
| 55 | bool ret = hEnumAssemblyRef.EnumNext(&(pAssemblyRefTokens[i])); |
| 56 | _ASSERTE(ret); |
| 57 | } |
| 58 | |
| 59 | *ppAssemblyRefTokens = pAssemblyRefTokens; |
| 60 | pAssemblyRefTokens = NULL; |
| 61 | |
| 62 | *pdwCAssemblyRefTokens= assemblyRefCount; |
| 63 | hr = S_OK; |
| 64 | |
| 65 | Exit: |
| 66 | SAFE_DELETE_ARRAY(pAssemblyRefTokens); |
| 67 | |
| 68 | return hr; |
| 69 | } |
| 70 | }; |
| 71 | |
| 72 | STDMETHODIMP Assembly::QueryInterface(REFIID riid, |
| 73 | void **ppv) |
| 74 | { |
| 75 | HRESULT hr = S_OK; |
| 76 | |
| 77 | if (ppv == NULL) |
| 78 | { |
| 79 | hr = E_POINTER; |
| 80 | } |
| 81 | else |
| 82 | { |
| 83 | if (IsEqualIID(riid, IID_IUnknown)) |
| 84 | { |
| 85 | AddRef(); |
| 86 | *ppv = static_cast<IUnknown *>(this); |
| 87 | } |
| 88 | else |
| 89 | { |
| 90 | *ppv = NULL; |
| 91 | hr = E_NOINTERFACE; |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | return hr; |
| 96 | } |
| 97 | |
| 98 | STDMETHODIMP_(ULONG) Assembly::AddRef() |
| 99 | { |
| 100 | return InterlockedIncrement(&m_cRef); |
| 101 | } |
| 102 | |
| 103 | STDMETHODIMP_(ULONG) Assembly::Release() |
| 104 | { |
| 105 | ULONG ulRef = InterlockedDecrement(&m_cRef); |
| 106 | |
| 107 | if (ulRef == 0) |
| 108 | { |
| 109 | delete this; |
| 110 | } |
| 111 | |
| 112 | return ulRef; |
| 113 | } |
| 114 | |
| 115 | Assembly::Assembly() |
| 116 | { |
| 117 | m_cRef = 1; |
| 118 | m_pPEImage = NULL; |
| 119 | m_pNativePEImage = NULL; |
| 120 | m_pAssemblyName = NULL; |
| 121 | m_pMDImport = NULL; |
| 122 | m_pAssemblyRefTokens = NULL; |
| 123 | m_dwCAssemblyRefTokens = static_cast<DWORD>(-1); |
| 124 | m_dwAssemblyFlags = FLAG_NONE; |
| 125 | m_pBinder = NULL; |
| 126 | } |
| 127 | |
| 128 | Assembly::~Assembly() |
| 129 | { |
| 130 | BINDER_LOG_ASSEMBLY_NAME(L"destructing assembly" , m_pAssemblyName); |
| 131 | |
| 132 | if (m_pPEImage != NULL) |
| 133 | { |
| 134 | BinderReleasePEImage(m_pPEImage); |
| 135 | m_pPEImage = NULL; |
| 136 | } |
| 137 | |
| 138 | #ifdef FEATURE_PREJIT |
| 139 | if (m_pNativePEImage != NULL) |
| 140 | { |
| 141 | BinderReleasePEImage(m_pNativePEImage); |
| 142 | m_pNativePEImage = NULL; |
| 143 | } |
| 144 | #endif |
| 145 | |
| 146 | SAFE_RELEASE(m_pAssemblyName); |
| 147 | SAFE_RELEASE(m_pMDImport); |
| 148 | SAFE_DELETE_ARRAY(m_pAssemblyRefTokens); |
| 149 | } |
| 150 | |
| 151 | HRESULT Assembly::Init( |
| 152 | IMDInternalImport *pIMetaDataAssemblyImport, |
| 153 | PEKIND PeKind, |
| 154 | PEImage *pPEImage, |
| 155 | PEImage *pNativePEImage, |
| 156 | SString &assemblyPath, |
| 157 | BOOL fInspectionOnly, |
| 158 | BOOL fIsInGAC) |
| 159 | { |
| 160 | HRESULT hr = S_OK; |
| 161 | BINDER_LOG_ENTER(L"Assembly::Init" ); |
| 162 | |
| 163 | ReleaseHolder<AssemblyName> pAssemblyName; |
| 164 | SAFE_NEW(pAssemblyName, AssemblyName); |
| 165 | |
| 166 | // Get assembly name def from meta data import and store it for later refs access |
| 167 | IF_FAIL_GO(pAssemblyName->Init(pIMetaDataAssemblyImport, PeKind)); |
| 168 | SetMDImport(pIMetaDataAssemblyImport); |
| 169 | if (!fIsInGAC) |
| 170 | { |
| 171 | GetPath().Set(assemblyPath); |
| 172 | } |
| 173 | |
| 174 | BINDER_LOG_ASSEMBLY_NAME(L"AssemblyNameDef" , pAssemblyName); |
| 175 | BINDER_LOG_STRING(L"System Architecture" , |
| 176 | AssemblyName::ArchitectureToString(GetSystemArchitecture())); |
| 177 | |
| 178 | // Safe architecture for validation |
| 179 | PEKIND kAssemblyArchitecture; |
| 180 | kAssemblyArchitecture = pAssemblyName->GetArchitecture(); |
| 181 | SetInspectionOnly(fInspectionOnly); |
| 182 | SetIsInGAC(fIsInGAC); |
| 183 | SetPEImage(pPEImage); |
| 184 | SetNativePEImage(pNativePEImage); |
| 185 | pAssemblyName->SetIsDefinition(TRUE); |
| 186 | |
| 187 | // Now take ownership of assembly names |
| 188 | SetAssemblyName(pAssemblyName.Extract(), FALSE /* fAddRef */); |
| 189 | |
| 190 | // Finally validate architecture |
| 191 | if (!fInspectionOnly && !IsValidArchitecture(kAssemblyArchitecture)) |
| 192 | { |
| 193 | // Assembly image can't be executed on this platform |
| 194 | IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT)); |
| 195 | } |
| 196 | |
| 197 | Exit: |
| 198 | BINDER_LOG_LEAVE_HR(L"Assembly::Init" , hr); |
| 199 | return hr; |
| 200 | } |
| 201 | |
| 202 | HRESULT Assembly::GetMVID(GUID *pMVID) |
| 203 | { |
| 204 | // Zero init the GUID incase we fail |
| 205 | ZeroMemory(pMVID, sizeof(GUID)); |
| 206 | |
| 207 | return m_pMDImport->GetScopeProps(NULL, pMVID); |
| 208 | } |
| 209 | |
| 210 | HRESULT Assembly::GetNextAssemblyNameRef(DWORD nIndex, |
| 211 | AssemblyName **ppAssemblyName) |
| 212 | { |
| 213 | HRESULT hr = S_OK; |
| 214 | BINDER_LOG_ENTER(L"Assembly::GetNextAssemblyNameRef" ); |
| 215 | |
| 216 | if (ppAssemblyName == NULL) |
| 217 | { |
| 218 | IF_FAIL_GO(E_INVALIDARG); |
| 219 | } |
| 220 | else if (GetNbAssemblyRefTokens() == static_cast<DWORD>(-1)) |
| 221 | { |
| 222 | mdAssembly *pAssemblyRefTokens = NULL; |
| 223 | DWORD dwCAssemblyRefTokens = 0; |
| 224 | |
| 225 | IF_FAIL_GO(BINDER_SPACE::GetAssemblyRefTokens(GetMDImport(), |
| 226 | &pAssemblyRefTokens, |
| 227 | &dwCAssemblyRefTokens)); |
| 228 | |
| 229 | if (InterlockedCompareExchangeT(&m_pAssemblyRefTokens, |
| 230 | pAssemblyRefTokens, |
| 231 | NULL)) |
| 232 | { |
| 233 | SAFE_DELETE_ARRAY(pAssemblyRefTokens); |
| 234 | } |
| 235 | SetNbAsssemblyRefTokens(dwCAssemblyRefTokens); |
| 236 | } |
| 237 | |
| 238 | _ASSERTE(GetNbAssemblyRefTokens() != static_cast<DWORD>(-1)); |
| 239 | |
| 240 | // Verify input index |
| 241 | if (nIndex >= GetNbAssemblyRefTokens()) |
| 242 | { |
| 243 | IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS)); |
| 244 | } |
| 245 | else |
| 246 | { |
| 247 | ReleaseHolder<AssemblyName> pAssemblyName; |
| 248 | |
| 249 | SAFE_NEW(pAssemblyName, AssemblyName); |
| 250 | IF_FAIL_GO(pAssemblyName->Init(GetMDImport(), |
| 251 | peNone, |
| 252 | GetAssemblyRefTokens()[nIndex], |
| 253 | FALSE /* fIsDefinition */)); |
| 254 | |
| 255 | *ppAssemblyName = pAssemblyName.Extract(); |
| 256 | } |
| 257 | |
| 258 | Exit: |
| 259 | BINDER_LOG_LEAVE_HR(L"Assembly::GetNextAssemblyNameRef" , hr); |
| 260 | return hr; |
| 261 | } |
| 262 | |
| 263 | /* static */ |
| 264 | PEKIND Assembly::GetSystemArchitecture() |
| 265 | { |
| 266 | #if defined(_TARGET_X86_) |
| 267 | return peI386; |
| 268 | #elif defined(_TARGET_AMD64_) |
| 269 | return peAMD64; |
| 270 | #elif defined(_TARGET_ARM_) |
| 271 | return peARM; |
| 272 | #elif defined(_TARGET_ARM64_) |
| 273 | return peARM64; |
| 274 | #else |
| 275 | PORTABILITY_ASSERT("Assembly::GetSystemArchitecture" ); |
| 276 | #endif |
| 277 | } |
| 278 | |
| 279 | /* static */ |
| 280 | BOOL Assembly::IsValidArchitecture(PEKIND kArchitecture) |
| 281 | { |
| 282 | if (!IsPlatformArchitecture(kArchitecture)) |
| 283 | return TRUE; |
| 284 | |
| 285 | return (kArchitecture == GetSystemArchitecture()); |
| 286 | } |
| 287 | |
| 288 | // -------------------------------------------------------------------- |
| 289 | // ICLRPrivAssembly methods |
| 290 | // -------------------------------------------------------------------- |
| 291 | LPCWSTR Assembly::GetSimpleName() |
| 292 | { |
| 293 | AssemblyName *pAsmName = GetAssemblyName(); |
| 294 | return (pAsmName == nullptr ? nullptr : pAsmName->GetSimpleName()); |
| 295 | } |
| 296 | |
| 297 | HRESULT Assembly::BindAssemblyByName(IAssemblyName * pIAssemblyName, ICLRPrivAssembly ** ppAssembly) |
| 298 | { |
| 299 | return (m_pBinder == NULL) ? E_FAIL : m_pBinder->BindAssemblyByName(pIAssemblyName, ppAssembly); |
| 300 | } |
| 301 | |
| 302 | HRESULT Assembly::GetBinderID(UINT_PTR *pBinderId) |
| 303 | { |
| 304 | return (m_pBinder == NULL) ? E_FAIL : m_pBinder->GetBinderID(pBinderId); |
| 305 | } |
| 306 | |
| 307 | HRESULT Assembly::GetLoaderAllocator(LPVOID* pLoaderAllocator) |
| 308 | { |
| 309 | return (m_pBinder == NULL) ? E_FAIL : m_pBinder->GetLoaderAllocator(pLoaderAllocator); |
| 310 | } |
| 311 | |
| 312 | HRESULT Assembly::IsShareable( |
| 313 | BOOL * pbIsShareable) |
| 314 | { |
| 315 | if(pbIsShareable == nullptr) |
| 316 | return E_INVALIDARG; |
| 317 | |
| 318 | *pbIsShareable = GetIsSharable(); |
| 319 | return S_OK; |
| 320 | } |
| 321 | |
| 322 | HRESULT Assembly::GetAvailableImageTypes( |
| 323 | LPDWORD pdwImageTypes) |
| 324 | { |
| 325 | HRESULT hr = E_FAIL; |
| 326 | |
| 327 | if(pdwImageTypes == nullptr) |
| 328 | return E_INVALIDARG; |
| 329 | |
| 330 | *pdwImageTypes = ASSEMBLY_IMAGE_TYPE_ASSEMBLY; |
| 331 | |
| 332 | return S_OK; |
| 333 | } |
| 334 | |
| 335 | HRESULT Assembly::GetImageResource( |
| 336 | DWORD dwImageType, |
| 337 | DWORD * pdwImageType, |
| 338 | ICLRPrivResource ** ppIResource) |
| 339 | { |
| 340 | HRESULT hr = S_OK; |
| 341 | if(ppIResource == nullptr) |
| 342 | return E_INVALIDARG; |
| 343 | |
| 344 | if ((dwImageType & ASSEMBLY_IMAGE_TYPE_ASSEMBLY) == ASSEMBLY_IMAGE_TYPE_ASSEMBLY) |
| 345 | { |
| 346 | *ppIResource = clr::SafeAddRef(&m_clrPrivRes); |
| 347 | if (pdwImageType != nullptr) |
| 348 | *pdwImageType = ASSEMBLY_IMAGE_TYPE_ASSEMBLY; |
| 349 | } |
| 350 | else |
| 351 | { |
| 352 | hr = CLR_E_BIND_IMAGE_UNAVAILABLE; |
| 353 | } |
| 354 | |
| 355 | return hr; |
| 356 | } |
| 357 | |
| 358 | // get parent pointer from nested type |
| 359 | #define GetPThis() ((BINDER_SPACE::Assembly*)(((PBYTE)this) - offsetof(BINDER_SPACE::Assembly, m_clrPrivRes))) |
| 360 | |
| 361 | HRESULT Assembly::CLRPrivResourceAssembly::QueryInterface(REFIID riid, void ** ppv) |
| 362 | { |
| 363 | HRESULT hr = S_OK; |
| 364 | VALIDATE_ARG_RET(ppv != NULL); |
| 365 | |
| 366 | if (IsEqualIID(riid, IID_IUnknown)) |
| 367 | { |
| 368 | AddRef(); |
| 369 | *ppv = this; |
| 370 | } |
| 371 | else if (IsEqualIID(riid, __uuidof(ICLRPrivResource))) |
| 372 | { |
| 373 | AddRef(); |
| 374 | // upcasting is safe |
| 375 | *ppv = static_cast<ICLRPrivResource *>(this); |
| 376 | } |
| 377 | else if (IsEqualIID(riid, __uuidof(ICLRPrivResourceAssembly))) |
| 378 | { |
| 379 | AddRef(); |
| 380 | *ppv = static_cast<ICLRPrivResourceAssembly *>(this); |
| 381 | } |
| 382 | else |
| 383 | { |
| 384 | *ppv = NULL; |
| 385 | hr = E_NOINTERFACE; |
| 386 | } |
| 387 | |
| 388 | return hr; |
| 389 | } |
| 390 | |
| 391 | ULONG Assembly::CLRPrivResourceAssembly::AddRef() |
| 392 | { |
| 393 | return GetPThis()->AddRef(); |
| 394 | } |
| 395 | |
| 396 | ULONG Assembly::CLRPrivResourceAssembly::Release() |
| 397 | { |
| 398 | return GetPThis()->Release(); |
| 399 | } |
| 400 | |
| 401 | HRESULT Assembly::CLRPrivResourceAssembly::GetResourceType(IID *pIID) |
| 402 | { |
| 403 | VALIDATE_ARG_RET(pIID != nullptr); |
| 404 | *pIID = __uuidof(ICLRPrivResourceAssembly); |
| 405 | return S_OK; |
| 406 | } |
| 407 | |
| 408 | HRESULT Assembly::CLRPrivResourceAssembly::GetAssembly(LPVOID *ppAssembly) |
| 409 | { |
| 410 | VALIDATE_ARG_RET(ppAssembly != nullptr); |
| 411 | AddRef(); |
| 412 | *ppAssembly = GetPThis(); |
| 413 | return S_OK; |
| 414 | } |
| 415 | |
| 416 | } |
| 417 | |
| 418 | |