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 | |