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 | // ApplicationContext.cpp |
7 | // |
8 | |
9 | |
10 | // |
11 | // Implements the ApplicationContext class |
12 | // |
13 | // ============================================================ |
14 | |
15 | #ifndef FEATURE_CORESYSTEM |
16 | #define DISABLE_BINDER_DEBUG_LOGGING |
17 | #endif |
18 | |
19 | #include "applicationcontext.hpp" |
20 | #include "stringarraylist.h" |
21 | #include "loadcontext.hpp" |
22 | #include "propertymap.hpp" |
23 | #include "failurecache.hpp" |
24 | #include "assemblyidentitycache.hpp" |
25 | #ifdef FEATURE_VERSIONING_LOG |
26 | #include "debuglog.hpp" |
27 | #endif // FEATURE_VERSIONING_LOG |
28 | #include "utils.hpp" |
29 | #include "variables.hpp" |
30 | #include "ex.h" |
31 | #include "clr/fs/path.h" |
32 | using namespace clr::fs; |
33 | |
34 | namespace BINDER_SPACE |
35 | { |
36 | STDMETHODIMP ApplicationContext::QueryInterface(REFIID riid, |
37 | void **ppv) |
38 | { |
39 | HRESULT hr = S_OK; |
40 | |
41 | if (ppv == NULL) |
42 | { |
43 | hr = E_POINTER; |
44 | } |
45 | else |
46 | { |
47 | if (IsEqualIID(riid, IID_IUnknown)) |
48 | { |
49 | AddRef(); |
50 | *ppv = static_cast<IUnknown *>(this); |
51 | } |
52 | else |
53 | { |
54 | *ppv = NULL; |
55 | hr = E_NOINTERFACE; |
56 | } |
57 | } |
58 | |
59 | return hr; |
60 | } |
61 | |
62 | STDMETHODIMP_(ULONG) ApplicationContext::AddRef() |
63 | { |
64 | return InterlockedIncrement(&m_cRef); |
65 | } |
66 | |
67 | STDMETHODIMP_(ULONG) ApplicationContext::Release() |
68 | { |
69 | ULONG ulRef = InterlockedDecrement(&m_cRef); |
70 | |
71 | if (ulRef == 0) |
72 | { |
73 | delete this; |
74 | } |
75 | |
76 | return ulRef; |
77 | } |
78 | |
79 | ApplicationContext::ApplicationContext() |
80 | { |
81 | m_cRef = 1; |
82 | m_dwAppDomainId = 0; |
83 | m_pExecutionContext = NULL; |
84 | m_pInspectionContext = NULL; |
85 | m_pFailureCache = NULL; |
86 | m_contextCS = NULL; |
87 | m_pTrustedPlatformAssemblyMap = nullptr; |
88 | m_pFileNameHash = nullptr; |
89 | } |
90 | |
91 | ApplicationContext::~ApplicationContext() |
92 | { |
93 | SAFE_RELEASE(m_pExecutionContext); |
94 | SAFE_RELEASE(m_pInspectionContext); |
95 | SAFE_DELETE(m_pFailureCache); |
96 | |
97 | if (m_contextCS != NULL) |
98 | { |
99 | ClrDeleteCriticalSection(m_contextCS); |
100 | } |
101 | |
102 | if (m_pTrustedPlatformAssemblyMap != nullptr) |
103 | { |
104 | delete m_pTrustedPlatformAssemblyMap; |
105 | } |
106 | |
107 | if (m_pFileNameHash != nullptr) |
108 | { |
109 | delete m_pFileNameHash; |
110 | } |
111 | } |
112 | |
113 | HRESULT ApplicationContext::Init() |
114 | { |
115 | HRESULT hr = S_OK; |
116 | BINDER_LOG_ENTER(W("ApplicationContext::Init" )); |
117 | BINDER_LOG_POINTER(W("this" ), this); |
118 | |
119 | ReleaseHolder<ExecutionContext> pExecutionContext; |
120 | ReleaseHolder<InspectionContext> pInspectionContext; |
121 | |
122 | PropertyMap *pPropertyMap = NULL; |
123 | FailureCache *pFailureCache = NULL; |
124 | |
125 | // Allocate context objects |
126 | SAFE_NEW(pExecutionContext, ExecutionContext); |
127 | SAFE_NEW(pInspectionContext, InspectionContext); |
128 | |
129 | SAFE_NEW(pFailureCache, FailureCache); |
130 | |
131 | m_contextCS = ClrCreateCriticalSection( |
132 | CrstFusionAppCtx, |
133 | CRST_REENTRANCY); |
134 | if (!m_contextCS) |
135 | { |
136 | SAFE_DELETE(pPropertyMap); |
137 | SAFE_DELETE(pFailureCache); |
138 | hr = E_OUTOFMEMORY; |
139 | } |
140 | else |
141 | { |
142 | m_pExecutionContext = pExecutionContext.Extract(); |
143 | m_pInspectionContext = pInspectionContext.Extract(); |
144 | |
145 | m_pFailureCache = pFailureCache; |
146 | } |
147 | |
148 | m_fCanExplicitlyBindToNativeImages = false; |
149 | |
150 | Exit: |
151 | BINDER_LOG_LEAVE_HR(W("ApplicationContext::Init" ), hr); |
152 | return hr; |
153 | } |
154 | |
155 | HRESULT GetNextPath(SString& paths, SString::Iterator& startPos, SString& outPath) |
156 | { |
157 | HRESULT hr = S_OK; |
158 | |
159 | bool wrappedWithQuotes = false; |
160 | |
161 | // Skip any leading spaces or path separators |
162 | while (paths.Skip(startPos, W(' ')) || paths.Skip(startPos, PATH_SEPARATOR_CHAR_W)) {} |
163 | |
164 | if (startPos == paths.End()) |
165 | { |
166 | // No more paths in the string and we just skipped over some white space |
167 | outPath.Set(W("" )); |
168 | return S_FALSE; |
169 | } |
170 | |
171 | // Support paths being wrapped with quotations |
172 | if (paths.Skip(startPos, W('\"'))) |
173 | { |
174 | wrappedWithQuotes = true; |
175 | } |
176 | |
177 | SString::Iterator iEnd = startPos; // Where current path ends |
178 | SString::Iterator iNext; // Where next path starts |
179 | if (wrappedWithQuotes) |
180 | { |
181 | if (paths.Find(iEnd, W('\"'))) |
182 | { |
183 | iNext = iEnd; |
184 | // Find where the next path starts - there should be a path separator right after the closing quotation mark |
185 | if (paths.Find(iNext, PATH_SEPARATOR_CHAR_W)) |
186 | { |
187 | iNext++; |
188 | } |
189 | else |
190 | { |
191 | iNext = paths.End(); |
192 | } |
193 | } |
194 | else |
195 | { |
196 | // There was no terminating quotation mark - that's bad |
197 | GO_WITH_HRESULT(E_INVALIDARG); |
198 | } |
199 | } |
200 | else if (paths.Find(iEnd, PATH_SEPARATOR_CHAR_W)) |
201 | { |
202 | iNext = iEnd + 1; |
203 | } |
204 | else |
205 | { |
206 | iNext = iEnd = paths.End(); |
207 | } |
208 | |
209 | // Skip any trailing spaces |
210 | while (iEnd[-1] == W(' ')) |
211 | { |
212 | iEnd--; |
213 | } |
214 | |
215 | _ASSERTE(startPos < iEnd); |
216 | |
217 | outPath.Set(paths, startPos, iEnd); |
218 | startPos = iNext; |
219 | Exit: |
220 | return hr; |
221 | } |
222 | |
223 | HRESULT ApplicationContext::SetupBindingPaths(SString &sTrustedPlatformAssemblies, |
224 | SString &sPlatformResourceRoots, |
225 | SString &sAppPaths, |
226 | SString &sAppNiPaths, |
227 | BOOL fAcquireLock) |
228 | { |
229 | HRESULT hr = S_OK; |
230 | BINDER_LOG_ENTER(W("ApplicationContext::SetupBindingPaths" )); |
231 | BINDER_LOG_POINTER(W("this" ), this); |
232 | |
233 | #ifndef CROSSGEN_COMPILE |
234 | CRITSEC_Holder contextLock(fAcquireLock ? GetCriticalSectionCookie() : NULL); |
235 | #endif |
236 | if (m_pTrustedPlatformAssemblyMap != nullptr) |
237 | { |
238 | #if defined(BINDER_DEBUG_LOG) |
239 | BINDER_LOG(W("ApplicationContext::SetupBindingPaths: Binding paths already setup" )); |
240 | #endif // BINDER_LOG_STRING |
241 | GO_WITH_HRESULT(S_OK); |
242 | } |
243 | |
244 | |
245 | // |
246 | // Parse TrustedPlatformAssemblies |
247 | // |
248 | m_pTrustedPlatformAssemblyMap = new SimpleNameToFileNameMap(); |
249 | m_pFileNameHash = new TpaFileNameHash(); |
250 | |
251 | sTrustedPlatformAssemblies.Normalize(); |
252 | |
253 | for (SString::Iterator i = sTrustedPlatformAssemblies.Begin(); i != sTrustedPlatformAssemblies.End(); ) |
254 | { |
255 | SString fileName; |
256 | HRESULT pathResult = S_OK; |
257 | IF_FAIL_GO(pathResult = GetNextPath(sTrustedPlatformAssemblies, i, fileName)); |
258 | if (pathResult == S_FALSE) |
259 | { |
260 | break; |
261 | } |
262 | |
263 | #ifndef CROSSGEN_COMPILE |
264 | if (Path::IsRelative(fileName)) |
265 | { |
266 | BINDER_LOG_STRING(W("ApplicationContext::SetupBindingPaths: Relative path not allowed" ), fileName); |
267 | GO_WITH_HRESULT(E_INVALIDARG); |
268 | } |
269 | #endif |
270 | |
271 | // Find the beginning of the simple name |
272 | SString::Iterator iSimpleNameStart = fileName.End(); |
273 | |
274 | if (!fileName.FindBack(iSimpleNameStart, DIRECTORY_SEPARATOR_CHAR_W)) |
275 | { |
276 | iSimpleNameStart = fileName.Begin(); |
277 | } |
278 | else |
279 | { |
280 | // Advance past the directory separator to the first character of the file name |
281 | iSimpleNameStart++; |
282 | } |
283 | |
284 | if (iSimpleNameStart == fileName.End()) |
285 | { |
286 | GO_WITH_HRESULT(E_INVALIDARG); |
287 | } |
288 | |
289 | SString simpleName; |
290 | bool isNativeImage = false; |
291 | |
292 | // GCC complains if we create SStrings inline as part of a function call |
293 | SString sNiDll(W(".ni.dll" )); |
294 | SString sNiExe(W(".ni.exe" )); |
295 | SString sNiWinmd(W(".ni.winmd" )); |
296 | SString sDll(W(".dll" )); |
297 | SString sExe(W(".exe" )); |
298 | SString sWinmd(W(".winmd" )); |
299 | |
300 | if (fileName.EndsWithCaseInsensitive(sNiDll) || |
301 | fileName.EndsWithCaseInsensitive(sNiExe)) |
302 | { |
303 | simpleName.Set(fileName, iSimpleNameStart, fileName.End() - 7); |
304 | isNativeImage = true; |
305 | } |
306 | else if (fileName.EndsWithCaseInsensitive(sNiWinmd)) |
307 | { |
308 | simpleName.Set(fileName, iSimpleNameStart, fileName.End() - 9); |
309 | isNativeImage = true; |
310 | } |
311 | else if (fileName.EndsWithCaseInsensitive(sDll) || |
312 | fileName.EndsWithCaseInsensitive(sExe)) |
313 | { |
314 | simpleName.Set(fileName, iSimpleNameStart, fileName.End() - 4); |
315 | } |
316 | else if (fileName.EndsWithCaseInsensitive(sWinmd)) |
317 | { |
318 | simpleName.Set(fileName, iSimpleNameStart, fileName.End() - 6); |
319 | } |
320 | else |
321 | { |
322 | // Invalid filename |
323 | GO_WITH_HRESULT(E_INVALIDARG); |
324 | } |
325 | |
326 | const SimpleNameToFileNameMapEntry *pExistingEntry = m_pTrustedPlatformAssemblyMap->LookupPtr(simpleName.GetUnicode()); |
327 | |
328 | if (pExistingEntry != nullptr) |
329 | { |
330 | // |
331 | // We want to store only the first entry matching a simple name we encounter. |
332 | // The exception is if we first store an IL reference and later in the string |
333 | // we encounter a native image. Since we don't touch IL in the presence of |
334 | // native images, we replace the IL entry with the NI. |
335 | // |
336 | if ((pExistingEntry->m_wszILFileName != nullptr && !isNativeImage) || |
337 | (pExistingEntry->m_wszNIFileName != nullptr && isNativeImage)) |
338 | { |
339 | BINDER_LOG_STRING(W("ApplicationContext::SetupBindingPaths: Skipping TPA entry because of already existing IL/NI entry for short name " ), fileName.GetUnicode()); |
340 | continue; |
341 | } |
342 | } |
343 | |
344 | LPWSTR wszSimpleName = nullptr; |
345 | if (pExistingEntry == nullptr) |
346 | { |
347 | wszSimpleName = new WCHAR[simpleName.GetCount() + 1]; |
348 | if (wszSimpleName == nullptr) |
349 | { |
350 | GO_WITH_HRESULT(E_OUTOFMEMORY); |
351 | } |
352 | wcscpy_s(wszSimpleName, simpleName.GetCount() + 1, simpleName.GetUnicode()); |
353 | } |
354 | else |
355 | { |
356 | wszSimpleName = pExistingEntry->m_wszSimpleName; |
357 | } |
358 | |
359 | LPWSTR wszFileName = new WCHAR[fileName.GetCount() + 1]; |
360 | if (wszFileName == nullptr) |
361 | { |
362 | GO_WITH_HRESULT(E_OUTOFMEMORY); |
363 | } |
364 | wcscpy_s(wszFileName, fileName.GetCount() + 1, fileName.GetUnicode()); |
365 | |
366 | SimpleNameToFileNameMapEntry mapEntry; |
367 | mapEntry.m_wszSimpleName = wszSimpleName; |
368 | if (isNativeImage) |
369 | { |
370 | mapEntry.m_wszNIFileName = wszFileName; |
371 | mapEntry.m_wszILFileName = pExistingEntry == nullptr ? nullptr : pExistingEntry->m_wszILFileName; |
372 | } |
373 | else |
374 | { |
375 | mapEntry.m_wszILFileName = wszFileName; |
376 | mapEntry.m_wszNIFileName = pExistingEntry == nullptr ? nullptr : pExistingEntry->m_wszNIFileName; |
377 | } |
378 | |
379 | m_pTrustedPlatformAssemblyMap->AddOrReplace(mapEntry); |
380 | |
381 | FileNameMapEntry fileNameExistenceEntry; |
382 | fileNameExistenceEntry.m_wszFileName = wszFileName; |
383 | m_pFileNameHash->AddOrReplace(fileNameExistenceEntry); |
384 | |
385 | BINDER_LOG_STRING(W("ApplicationContext::SetupBindingPaths: Added TPA entry" ), wszFileName); |
386 | } |
387 | |
388 | // |
389 | // Parse PlatformResourceRoots |
390 | // |
391 | sPlatformResourceRoots.Normalize(); |
392 | for (SString::Iterator i = sPlatformResourceRoots.Begin(); i != sPlatformResourceRoots.End(); ) |
393 | { |
394 | SString pathName; |
395 | HRESULT pathResult = S_OK; |
396 | |
397 | IF_FAIL_GO(pathResult = GetNextPath(sPlatformResourceRoots, i, pathName)); |
398 | if (pathResult == S_FALSE) |
399 | { |
400 | break; |
401 | } |
402 | |
403 | #ifndef CROSSGEN_COMPILE |
404 | if (Path::IsRelative(pathName)) |
405 | { |
406 | BINDER_LOG_STRING(W("ApplicationContext::SetupBindingPaths: Relative path not allowed" ), pathName); |
407 | GO_WITH_HRESULT(E_INVALIDARG); |
408 | } |
409 | #endif |
410 | |
411 | m_platformResourceRoots.Append(pathName); |
412 | BINDER_LOG_STRING(W("ApplicationContext::SetupBindingPaths: Added resource root" ), pathName); |
413 | } |
414 | |
415 | // |
416 | // Parse AppPaths |
417 | // |
418 | sAppPaths.Normalize(); |
419 | for (SString::Iterator i = sAppPaths.Begin(); i != sAppPaths.End(); ) |
420 | { |
421 | SString pathName; |
422 | HRESULT pathResult = S_OK; |
423 | |
424 | IF_FAIL_GO(pathResult = GetNextPath(sAppPaths, i, pathName)); |
425 | if (pathResult == S_FALSE) |
426 | { |
427 | break; |
428 | } |
429 | |
430 | #ifndef CROSSGEN_COMPILE |
431 | if (Path::IsRelative(pathName)) |
432 | { |
433 | BINDER_LOG_STRING(W("ApplicationContext::SetupBindingPaths: Relative path not allowed" ), pathName); |
434 | GO_WITH_HRESULT(E_INVALIDARG); |
435 | } |
436 | #endif |
437 | |
438 | m_appPaths.Append(pathName); |
439 | BINDER_LOG_STRING(W("ApplicationContext::SetupBindingPaths: Added App Path" ), pathName); |
440 | } |
441 | |
442 | // |
443 | // Parse AppNiPaths |
444 | // |
445 | sAppNiPaths.Normalize(); |
446 | for (SString::Iterator i = sAppNiPaths.Begin(); i != sAppNiPaths.End(); ) |
447 | { |
448 | SString pathName; |
449 | HRESULT pathResult = S_OK; |
450 | |
451 | IF_FAIL_GO(pathResult = GetNextPath(sAppNiPaths, i, pathName)); |
452 | if (pathResult == S_FALSE) |
453 | { |
454 | break; |
455 | } |
456 | |
457 | #ifndef CROSSGEN_COMPILE |
458 | if (Path::IsRelative(pathName)) |
459 | { |
460 | BINDER_LOG_STRING(W("ApplicationContext::SetupBindingPaths: Relative path not allowed" ), pathName); |
461 | GO_WITH_HRESULT(E_INVALIDARG); |
462 | } |
463 | #endif |
464 | |
465 | m_appNiPaths.Append(pathName); |
466 | BINDER_LOG_STRING(W("ApplicationContext::SetupBindingPaths: Added App NI Path" ), pathName); |
467 | } |
468 | |
469 | Exit: |
470 | BINDER_LOG_LEAVE_HR(W("ApplicationContext::SetupBindingPaths" ), hr); |
471 | return hr; |
472 | } |
473 | |
474 | HRESULT ApplicationContext::GetAssemblyIdentity(LPCSTR szTextualIdentity, |
475 | AssemblyIdentityUTF8 **ppAssemblyIdentity) |
476 | { |
477 | HRESULT hr = S_OK; |
478 | BINDER_LOG_ENTER(W("ApplicationContext::GetAssemblyIdentity" )); |
479 | BINDER_LOG_POINTER(W("this" ), this); |
480 | |
481 | _ASSERTE(szTextualIdentity != NULL); |
482 | _ASSERTE(ppAssemblyIdentity != NULL); |
483 | |
484 | CRITSEC_Holder contextLock(GetCriticalSectionCookie()); |
485 | |
486 | AssemblyIdentityUTF8 *pAssemblyIdentity = m_assemblyIdentityCache.Lookup(szTextualIdentity); |
487 | if (pAssemblyIdentity == NULL) |
488 | { |
489 | NewHolder<AssemblyIdentityUTF8> pNewAssemblyIdentity; |
490 | SString sTextualIdentity; |
491 | |
492 | SAFE_NEW(pNewAssemblyIdentity, AssemblyIdentityUTF8); |
493 | sTextualIdentity.SetUTF8(szTextualIdentity); |
494 | |
495 | IF_FAIL_GO(TextualIdentityParser::Parse(sTextualIdentity, pNewAssemblyIdentity)); |
496 | IF_FAIL_GO(m_assemblyIdentityCache.Add(szTextualIdentity, pNewAssemblyIdentity)); |
497 | |
498 | pNewAssemblyIdentity->PopulateUTF8Fields(); |
499 | |
500 | pAssemblyIdentity = pNewAssemblyIdentity.Extract(); |
501 | } |
502 | |
503 | *ppAssemblyIdentity = pAssemblyIdentity; |
504 | |
505 | Exit: |
506 | BINDER_LOG_LEAVE_HR(W("ApplicationContext::GetAssemblyIdentity" ), hr); |
507 | return hr; |
508 | } |
509 | |
510 | bool ApplicationContext::IsTpaListProvided() |
511 | { |
512 | return m_pTrustedPlatformAssemblyMap != nullptr; |
513 | } |
514 | }; |
515 | |