aboutsummaryrefslogtreecommitdiff
path: root/src/ext/Bal/dnchost/dncutil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ext/Bal/dnchost/dncutil.cpp')
-rw-r--r--src/ext/Bal/dnchost/dncutil.cpp411
1 files changed, 411 insertions, 0 deletions
diff --git a/src/ext/Bal/dnchost/dncutil.cpp b/src/ext/Bal/dnchost/dncutil.cpp
new file mode 100644
index 00000000..34d14911
--- /dev/null
+++ b/src/ext/Bal/dnchost/dncutil.cpp
@@ -0,0 +1,411 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3#include "precomp.h"
4
5// https://github.com/dotnet/runtime/blob/master/src/installer/corehost/error_codes.h
6#define InvalidArgFailure 0x80008081
7#define HostApiBufferTooSmall 0x80008098
8#define HostApiUnsupportedVersion 0x800080a2
9
10// internal function declarations
11
12static HRESULT GetHostfxrPath(
13 __in HOSTFXR_STATE* pState,
14 __in LPCWSTR wzNativeHostPath
15 );
16static HRESULT LoadHostfxr(
17 __in HOSTFXR_STATE* pState
18 );
19static HRESULT InitializeHostfxr(
20 __in HOSTFXR_STATE* pState,
21 __in LPCWSTR wzManagedHostPath,
22 __in LPCWSTR wzDepsJsonPath,
23 __in LPCWSTR wzRuntimeConfigPath
24 );
25static HRESULT InitializeCoreClr(
26 __in HOSTFXR_STATE* pState,
27 __in LPCWSTR wzNativeHostPath
28 );
29static HRESULT InitializeCoreClrPre5(
30 __in HOSTFXR_STATE* pState,
31 __in LPCWSTR wzNativeHostPath
32 );
33static HRESULT LoadCoreClr(
34 __in HOSTFXR_STATE* pState,
35 __in LPCWSTR wzCoreClrPath
36 );
37static HRESULT StartCoreClr(
38 __in HOSTFXR_STATE* pState,
39 __in LPCWSTR wzNativeHostPath,
40 __in DWORD cProperties,
41 __in LPCWSTR* propertyKeys,
42 __in LPCWSTR* propertyValues
43 );
44
45
46// function definitions
47
48HRESULT DnchostLoadRuntime(
49 __in HOSTFXR_STATE* pState,
50 __in LPCWSTR wzNativeHostPath,
51 __in LPCWSTR wzManagedHostPath,
52 __in LPCWSTR wzDepsJsonPath,
53 __in LPCWSTR wzRuntimeConfigPath
54 )
55{
56 HRESULT hr = S_OK;
57
58 hr = GetHostfxrPath(pState, wzNativeHostPath);
59 BalExitOnFailure(hr, "Failed to find hostfxr.");
60
61 hr = LoadHostfxr(pState);
62 BalExitOnFailure(hr, "Failed to load hostfxr.");
63
64 hr = InitializeHostfxr(pState, wzManagedHostPath, wzDepsJsonPath, wzRuntimeConfigPath);
65 BalExitOnFailure(hr, "Failed to initialize hostfxr.");
66
67 hr = InitializeCoreClr(pState, wzNativeHostPath);
68 BalExitOnFailure(hr, "Failed to initialize coreclr.");
69
70LExit:
71 return hr;
72}
73
74HRESULT DnchostCreateFactory(
75 __in HOSTFXR_STATE* pState,
76 __in LPCWSTR wzBaFactoryAssemblyName,
77 __in LPCWSTR wzBaFactoryAssemblyPath,
78 __out IBootstrapperApplicationFactory** ppAppFactory
79 )
80{
81 HRESULT hr = S_OK;
82 PFNCREATEBAFACTORY pfnCreateBAFactory = NULL;
83
84 if (pState->pfnGetFunctionPointer)
85 {
86 hr = pState->pfnGetFunctionPointer(
87 DNC_ENTRY_TYPEW,
88 DNC_STATIC_ENTRY_METHODW,
89 DNC_STATIC_ENTRY_DELEGATEW,
90 NULL,
91 NULL,
92 reinterpret_cast<void**>(&pfnCreateBAFactory));
93 BalExitOnFailure(hr, "Failed to create delegate through GetFunctionPointer.");
94 }
95 else
96 {
97 hr = pState->pfnCoreclrCreateDelegate(
98 pState->pClrHandle,
99 pState->dwDomainId,
100 DNC_ASSEMBLY_FULL_NAME,
101 DNC_ENTRY_TYPE,
102 DNC_STATIC_ENTRY_METHOD,
103 reinterpret_cast<void**>(&pfnCreateBAFactory));
104 BalExitOnFailure(hr, "Failed to create delegate in app domain.");
105 }
106
107 *ppAppFactory = pfnCreateBAFactory(wzBaFactoryAssemblyName, wzBaFactoryAssemblyPath);
108
109LExit:
110 return hr;
111}
112
113static HRESULT GetHostfxrPath(
114 __in HOSTFXR_STATE* pState,
115 __in LPCWSTR wzNativeHostPath
116 )
117{
118 HRESULT hr = S_OK;
119 get_hostfxr_parameters getHostfxrParameters = { };
120 int nrc = 0;
121 size_t cchHostFxrPath = MAX_PATH;
122
123 getHostfxrParameters.size = sizeof(get_hostfxr_parameters);
124 getHostfxrParameters.assembly_path = wzNativeHostPath;
125
126 // get_hostfxr_path does a full search on every call, so
127 // minimize the number of calls
128 // need to loop
129 for (;;)
130 {
131 cchHostFxrPath *= 2;
132 hr = StrAlloc(&pState->sczHostfxrPath, cchHostFxrPath);
133 BalExitOnFailure(hr, "Failed to allocate hostFxrPath.");
134
135 nrc = get_hostfxr_path(pState->sczHostfxrPath, &cchHostFxrPath, &getHostfxrParameters);
136 if (HostApiBufferTooSmall != nrc)
137 {
138 break;
139 }
140 }
141 if (0 != nrc)
142 {
143 BalExitOnFailure(hr = nrc, "GetHostfxrPath failed");
144 }
145
146LExit:
147 return hr;
148}
149
150static HRESULT LoadHostfxr(
151 __in HOSTFXR_STATE* pState
152 )
153{
154 HRESULT hr = S_OK;
155 HMODULE hHostfxr;
156
157 hHostfxr = ::LoadLibraryExW(pState->sczHostfxrPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
158 BalExitOnNullWithLastError(hHostfxr, hr, "Failed to load hostfxr from '%ls'.", pState->sczHostfxrPath);
159
160 pState->pfnHostfxrInitializeForApp = reinterpret_cast<hostfxr_initialize_for_dotnet_command_line_fn>(::GetProcAddress(hHostfxr, "hostfxr_initialize_for_dotnet_command_line"));
161 BalExitOnNullWithLastError(pState->pfnHostfxrInitializeForApp, hr, "Failed to get procedure address for hostfxr_initialize_for_dotnet_command_line.");
162
163 pState->pfnHostfxrGetRuntimeProperties = reinterpret_cast<hostfxr_get_runtime_properties_fn>(::GetProcAddress(hHostfxr, "hostfxr_get_runtime_properties"));
164 BalExitOnNullWithLastError(pState->pfnHostfxrGetRuntimeProperties, hr, "Failed to get procedure address for hostfxr_get_runtime_properties.");
165
166 pState->pfnHostfxrSetErrorWriter = reinterpret_cast<hostfxr_set_error_writer_fn>(::GetProcAddress(hHostfxr, "hostfxr_set_error_writer"));
167 BalExitOnNullWithLastError(pState->pfnHostfxrSetErrorWriter, hr, "Failed to get procedure address for hostfxr_set_error_writer.");
168
169 pState->pfnHostfxrClose = reinterpret_cast<hostfxr_close_fn>(::GetProcAddress(hHostfxr, "hostfxr_close"));
170 BalExitOnNullWithLastError(pState->pfnHostfxrClose, hr, "Failed to get procedure address for hostfxr_close.");
171
172 pState->pfnHostfxrGetRuntimeDelegate = reinterpret_cast<hostfxr_get_runtime_delegate_fn>(::GetProcAddress(hHostfxr, "hostfxr_get_runtime_delegate"));
173 BalExitOnNullWithLastError(pState->pfnHostfxrGetRuntimeDelegate, hr, "Failed to get procedure address for hostfxr_get_runtime_delegate.");
174
175LExit:
176 // Never unload the module since it isn't meant to be unloaded.
177
178 return hr;
179}
180
181static void HOSTFXR_CALLTYPE DnchostErrorWriter(
182 __in LPCWSTR wzMessage
183 )
184{
185 BOOTSTRAPPER_LOG_LEVEL level = BOOTSTRAPPER_LOG_LEVEL_ERROR;
186
187 if (CSTR_EQUAL == ::CompareString(LOCALE_INVARIANT, 0, wzMessage, -1, L"The requested delegate type is not available in the target framework.", -1))
188 {
189 level = BOOTSTRAPPER_LOG_LEVEL_DEBUG;
190 }
191
192 BalLog(level, "error from hostfxr: %ls", wzMessage);
193}
194
195static HRESULT InitializeHostfxr(
196 __in HOSTFXR_STATE* pState,
197 __in LPCWSTR wzManagedHostPath,
198 __in LPCWSTR wzDepsJsonPath,
199 __in LPCWSTR wzRuntimeConfigPath
200 )
201{
202 HRESULT hr = S_OK;
203
204 pState->pfnHostfxrSetErrorWriter(static_cast<hostfxr_error_writer_fn>(&DnchostErrorWriter));
205
206 LPCWSTR argv[] = {
207 L"exec",
208 L"--depsfile",
209 wzDepsJsonPath,
210 L"--runtimeconfig",
211 wzRuntimeConfigPath,
212 wzManagedHostPath,
213 };
214 hr = pState->pfnHostfxrInitializeForApp(sizeof(argv)/sizeof(LPWSTR), argv, NULL, &pState->hostContextHandle);
215 BalExitOnFailure(hr, "HostfxrInitializeForApp failed");
216
217LExit:
218 return hr;
219}
220
221static HRESULT InitializeCoreClr(
222 __in HOSTFXR_STATE* pState,
223 __in LPCWSTR wzNativeHostPath
224 )
225{
226 HRESULT hr = S_OK;
227
228 hr = pState->pfnHostfxrGetRuntimeDelegate(pState->hostContextHandle, hdt_get_function_pointer, reinterpret_cast<void**>(&pState->pfnGetFunctionPointer));
229 if (InvalidArgFailure == hr || // old versions of hostfxr don't allow calling GetRuntimeDelegate from InitializeForApp.
230 HostApiUnsupportedVersion == hr) // hdt_get_function_pointer was added in .NET 5.
231 {
232 hr = InitializeCoreClrPre5(pState, wzNativeHostPath);
233 }
234 else
235 {
236 ExitOnFailure(hr, "HostfxrGetRuntimeDelegate failed");
237 }
238
239LExit:
240 return hr;
241}
242
243static HRESULT InitializeCoreClrPre5(
244 __in HOSTFXR_STATE* pState,
245 __in LPCWSTR wzNativeHostPath
246 )
247{
248 HRESULT hr = S_OK;
249 int32_t rc = 0;
250 LPCWSTR* rgPropertyKeys = NULL;
251 LPCWSTR* rgPropertyValues = NULL;
252 size_t cProperties = 0;
253 LPWSTR* rgDirectories = NULL;
254 UINT cDirectories = 0;
255 LPWSTR sczCoreClrPath = NULL;
256
257 // We are not using hostfxr as it was intended to be used. We need to initialize hostfxr so that it properly initializes hostpolicy -
258 // there are pieces of the framework such as AssemblyDependencyResolver that won't work without that. We also need hostfxr to find a
259 // compatible framework for framework-dependent deployed BAs. We had to use hostfxr_initialize_for_dotnet_command_line since
260 // hostfxr_initialize_for_runtime_config doesn't currently (3.x) support self-contained deployed BAs. That means we're supposed to
261 // start the runtime through hostfxr_run_app, but that method shuts down the runtime before returning. We actually want to call
262 // hostfxr_get_runtime_delegate, but that method currently requires hostfxr to be initialized through
263 // hostfxr_initialize_for_runtime_config. So we're forced to locate coreclr.dll and manually load the runtime ourselves.
264
265 // Unfortunately, that's not the only problem. hostfxr has global state that tracks whether it started the runtime. While we keep our
266 // hostfxr_handle open, everyone that calls the hostfxr_initialize_* methods will block until we have started the runtime through
267 // hostfxr or closed our handle. If we close the handle, then hostfxr could potentially try to load a second runtime into the
268 // process, which is not supported. We're going to just keep our handle open since no one else in the process should be trying to
269 // start the runtime anyway.
270
271 rc = pState->pfnHostfxrGetRuntimeProperties(pState->hostContextHandle, &cProperties, rgPropertyKeys, rgPropertyValues);
272 if (HostApiBufferTooSmall != rc)
273 {
274 BalExitOnFailure(hr = rc, "HostfxrGetRuntimeProperties failed to return required size.");
275 }
276
277 rgPropertyKeys = static_cast<LPCWSTR*>(MemAlloc(sizeof(LPWSTR) * cProperties, TRUE));
278 rgPropertyValues = static_cast<LPCWSTR*>(MemAlloc(sizeof(LPWSTR) * cProperties, TRUE));
279 if (!rgPropertyKeys || !rgPropertyValues)
280 {
281 BalExitOnFailure(hr = E_OUTOFMEMORY, "Failed to allocate buffers for runtime properties.");
282 }
283
284 hr = pState->pfnHostfxrGetRuntimeProperties(pState->hostContextHandle, &cProperties, rgPropertyKeys, rgPropertyValues);
285 BalExitOnFailure(hr, "HostfxrGetRuntimeProperties failed.");
286
287 for (DWORD i = 0; i < cProperties; ++i)
288 {
289 if (CSTR_EQUAL == ::CompareString(LOCALE_INVARIANT, 0, rgPropertyKeys[i], -1, L"NATIVE_DLL_SEARCH_DIRECTORIES", -1))
290 {
291 hr = StrSplitAllocArray(&rgDirectories, &cDirectories, rgPropertyValues[i], L";");
292 BalExitOnFailure(hr, "Failed to split NATIVE_DLL_SEARCH_DIRECTORIES '%ls'", rgPropertyValues[i]);
293 }
294 }
295
296 for (DWORD i = 0; i < cDirectories; ++i)
297 {
298 hr = PathConcat(rgDirectories[i], L"coreclr.dll", &sczCoreClrPath);
299 BalExitOnFailure(hr, "Failed to allocate path to coreclr.");
300
301 if (::PathFileExists(sczCoreClrPath))
302 {
303 break;
304 }
305 else
306 {
307 ReleaseNullStr(sczCoreClrPath);
308 }
309 }
310
311 if (!sczCoreClrPath)
312 {
313 for (DWORD i = 0; i < cProperties; ++i)
314 {
315 BalLog(BOOTSTRAPPER_LOG_LEVEL_ERROR, "%ls: %ls", rgPropertyKeys[i], rgPropertyValues[i]);
316 }
317 BalExitOnFailure(hr = E_FILENOTFOUND, "Failed to locate coreclr.dll.");
318 }
319
320 hr = LoadCoreClr(pState, sczCoreClrPath);
321 BalExitOnFailure(hr, "Failed to load coreclr.");
322
323 hr = StartCoreClr(pState, wzNativeHostPath, (DWORD)cProperties, rgPropertyKeys, rgPropertyValues);
324 BalExitOnFailure(hr, "Failed to start coreclr.");
325
326LExit:
327 MemFree(rgDirectories);
328 MemFree(rgPropertyValues);
329 MemFree(rgPropertyKeys);
330 ReleaseStr(sczCoreClrPath);
331
332 return hr;
333}
334
335static HRESULT LoadCoreClr(
336 __in HOSTFXR_STATE* pState,
337 __in LPCWSTR wzCoreClrPath
338 )
339{
340 HRESULT hr = S_OK;
341 HMODULE hModule = NULL;
342
343 hModule = ::LoadLibraryExW(wzCoreClrPath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
344 BalExitOnNullWithLastError(hModule, hr, "Failed to load coreclr.dll from '%ls'.", wzCoreClrPath);
345
346 pState->pfnCoreclrInitialize = reinterpret_cast<coreclr_initialize_ptr>(::GetProcAddress(hModule, "coreclr_initialize"));
347 BalExitOnNullWithLastError(pState->pfnCoreclrInitialize, hr, "Failed to get procedure address for coreclr_initialize.");
348
349 pState->pfnCoreclrCreateDelegate = reinterpret_cast<coreclr_create_delegate_ptr>(::GetProcAddress(hModule, "coreclr_create_delegate"));
350 BalExitOnNullWithLastError(pState->pfnCoreclrCreateDelegate, hr, "Failed to get procedure address for coreclr_create_delegate.");
351
352LExit:
353 // Never unload the module since coreclr doesn't support it.
354
355 return hr;
356}
357
358static HRESULT StartCoreClr(
359 __in HOSTFXR_STATE* pState,
360 __in LPCWSTR wzNativeHostPath,
361 __in DWORD cProperties,
362 __in LPCWSTR* propertyKeys,
363 __in LPCWSTR* propertyValues
364 )
365{
366 HRESULT hr = S_OK;
367 LPSTR szNativeHostPath = NULL;
368 LPSTR* rgPropertyKeys = NULL;
369 LPSTR* rgPropertyValues = NULL;
370
371 rgPropertyKeys = static_cast<LPSTR*>(MemAlloc(sizeof(LPSTR) * cProperties, TRUE));
372 rgPropertyValues = static_cast<LPSTR*>(MemAlloc(sizeof(LPSTR) * cProperties, TRUE));
373 if (!rgPropertyKeys || !rgPropertyValues)
374 {
375 BalExitOnFailure(hr = E_OUTOFMEMORY, "Failed to allocate buffers for runtime properties.");
376 }
377
378 hr = StrAnsiAllocString(&szNativeHostPath, wzNativeHostPath, 0, CP_UTF8);
379 BalExitOnFailure(hr, "Failed to convert module path to UTF8: %ls", wzNativeHostPath);
380
381 for (DWORD i = 0; i < cProperties; ++i)
382 {
383 hr = StrAnsiAllocString(&rgPropertyKeys[i], propertyKeys[i], 0, CP_UTF8);
384 BalExitOnFailure(hr, "Failed to convert property key to UTF8: %ls", propertyKeys[i]);
385
386 hr = StrAnsiAllocString(&rgPropertyValues[i], propertyValues[i], 0, CP_UTF8);
387 BalExitOnFailure(hr, "Failed to convert property value to UTF8: %ls", propertyValues[i]);
388 }
389
390 hr = pState->pfnCoreclrInitialize(szNativeHostPath, "MBA", cProperties, (LPCSTR*)rgPropertyKeys, (LPCSTR*)rgPropertyValues, &pState->pClrHandle, &pState->dwDomainId);
391 BalExitOnFailure(hr, "CoreclrInitialize failed.");
392
393LExit:
394 for (DWORD i = 0; i < cProperties; ++i)
395 {
396 if (rgPropertyKeys)
397 {
398 ReleaseStr(rgPropertyKeys[i]);
399 }
400
401 if (rgPropertyValues)
402 {
403 ReleaseStr(rgPropertyValues[i]);
404 }
405 }
406 ReleaseMem(rgPropertyValues);
407 ReleaseMem(rgPropertyKeys);
408 ReleaseStr(szNativeHostPath);
409
410 return hr;
411}