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
19namespace 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
65Exit:
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