Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public static partial class HostWriter

public class DotNetSearchOptions
{
// Keep in sync with fxr_resolver::search_location in fxr_resolver.h
// Keep in sync with fxr_search_location in fxr_resolver.h
[Flags]
public enum SearchLocation : byte
{
Expand Down
2 changes: 1 addition & 1 deletion src/native/corehost/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ endif()

if(NOT CLR_CMAKE_TARGET_BROWSER)
add_library(fxr_resolver INTERFACE)
target_sources(fxr_resolver INTERFACE fxr_resolver.cpp fxr_resolver.c)
target_sources(fxr_resolver INTERFACE fxr_resolver.c)
target_include_directories(fxr_resolver INTERFACE fxr)

add_compile_definitions(RAPIDJSON_HAS_CXX17)
Expand Down
31 changes: 25 additions & 6 deletions src/native/corehost/apphost/standalone/hostfxr_resolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include "pal.h"
#include "fxr_resolver.h"
#include "trace.h"
#include "utils.h"
#include "error_codes.h"
#include "hostfxr_resolver.h"

namespace
Expand All @@ -14,22 +16,22 @@ namespace
#define EMBED_DOTNET_SEARCH_HI_PART_UTF8 "19ff3e9c3602ae8e841925bb461a0adb"
#define EMBED_DOTNET_SEARCH_LO_PART_UTF8 "064a1f1903667a5e0d87e8f608f425ac"

// <fxr_resolver::search_location_default> \0 <app_relative_dotnet_placeholder>
// <fxr_search_location_default> \0 <app_relative_dotnet_placeholder>
#define EMBED_DOTNET_SEARCH_FULL_UTF8 ("\0\0" EMBED_DOTNET_SEARCH_HI_PART_UTF8 EMBED_DOTNET_SEARCH_LO_PART_UTF8)

// Get the .NET search options that should be used
// Returns false if options are invalid - for example, app-relative search was specified, but the path is invalid or not embedded
bool try_get_dotnet_search_options(fxr_resolver::search_location& out_search_location, pal::string_t& out_app_relative_dotnet)
bool try_get_dotnet_search_options(fxr_search_location& out_search_location, pal::string_t& out_app_relative_dotnet)
{
constexpr int EMBED_SIZE = 512;
static_assert(sizeof(EMBED_DOTNET_SEARCH_FULL_UTF8) / sizeof(EMBED_DOTNET_SEARCH_FULL_UTF8[0]) < EMBED_SIZE, "Placeholder value for .NET search options longer than expected");

// Contains the EMBED_DOTNET_SEARCH_FULL_UTF8 value at compile time or app-relative .NET path written by the SDK (dotnet publish).
static char embed[EMBED_SIZE] = EMBED_DOTNET_SEARCH_FULL_UTF8;

out_search_location = (fxr_resolver::search_location)embed[0];
out_search_location = (fxr_search_location)embed[0];
assert(embed[1] == 0); // NUL separates the search location and embedded .NET root value
if ((out_search_location & fxr_resolver::search_location_app_relative) == 0)
if ((out_search_location & fxr_search_location_app_relative) == 0)
return true;

// Get the embedded app-relative .NET path
Expand Down Expand Up @@ -98,7 +100,7 @@ hostfxr_main_fn hostfxr_resolver_t::resolve_main_v1()

hostfxr_resolver_t::hostfxr_resolver_t(const pal::string_t& app_root)
{
fxr_resolver::search_location search_location = fxr_resolver::search_location_default;
fxr_search_location search_location = fxr_search_location_default;
pal::string_t app_relative_dotnet;
pal::string_t app_relative_dotnet_path;
if (!try_get_dotnet_search_options(search_location, app_relative_dotnet))
Expand All @@ -114,7 +116,24 @@ hostfxr_resolver_t::hostfxr_resolver_t(const pal::string_t& app_root)
append_path(&app_relative_dotnet_path, app_relative_dotnet.c_str());
}

if (!fxr_resolver::try_get_path(app_root, search_location, &app_relative_dotnet_path, &m_dotnet_root, &m_fxr_path))
pal_char_t* dotnet_root = nullptr;
pal_char_t* fxr_path = nullptr;
bool resolved = fxr_resolver_try_get_path(
app_root.c_str(),
search_location,
app_relative_dotnet_path.empty() ? nullptr : app_relative_dotnet_path.c_str(),
&dotnet_root,
&fxr_path);
if (resolved)
{
m_dotnet_root.assign(dotnet_root);
m_fxr_path.assign(fxr_path);
}

free(dotnet_root);
free(fxr_path);

if (!resolved)
{
m_status_code = StatusCode::CoreHostLibMissingFailure;
}
Expand Down
1 change: 0 additions & 1 deletion src/native/corehost/apphost/static/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ set(SOURCES
./hostfxr_resolver.cpp
./hostpolicy_resolver.cpp
../../hostpolicy/static/coreclr_resolver.cpp
../../fxr_resolver.cpp
../../fxr_resolver.c
../../corehost.cpp
)
Expand Down
2 changes: 1 addition & 1 deletion src/native/corehost/comhost/comhost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include "comhost.h"
#include "redirected_error_writer.h"
#include "hostfxr.h"
#include "fxr_resolver.h"
#include "load_fxr_and_get_delegate.h"
#include "pal.h"
#include "trace.h"
#include "error_codes.h"
Expand Down
16 changes: 12 additions & 4 deletions src/native/corehost/fxr_resolver.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

// C implementation of the fxr_resolver_* APIs (the C++ fxr_resolver:: namespace
// in fxr_resolver.cpp now delegates here). try_get_existing_fxr stays in C++
// because pal::get_loaded_library is templated/typed for C++ callers.

#include "fxr_resolver.h"

#include "fx_ver.h"
Expand Down Expand Up @@ -443,3 +439,15 @@ bool fxr_resolver_try_get_path_from_dotnet_root(
free(fxr_dir);
return ok;
}

bool fxr_resolver_try_get_existing_fxr(pal_dll_t* out_fxr, pal_char_t** out_fxr_path)
{
*out_fxr = NULL;
*out_fxr_path = NULL;

if (!pal_get_loaded_library(LIBFXR_NAME, "hostfxr_main", out_fxr, out_fxr_path))
return false;

trace_verbose(_X("Found previously loaded library %s [%s]."), LIBFXR_NAME, *out_fxr_path);
return true;
}
66 changes: 0 additions & 66 deletions src/native/corehost/fxr_resolver.cpp

This file was deleted.

131 changes: 8 additions & 123 deletions src/native/corehost/fxr_resolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
extern "C" {
#endif

// Keep in sync with fxr_resolver::search_location below and with
// DotNetRootOptions.SearchLocation in HostWriter.cs.
// Keep in sync with DotNetRootOptions.SearchLocation in HostWriter.cs.
typedef enum
{
fxr_search_location_default = 0,
Expand All @@ -37,129 +36,15 @@ bool fxr_resolver_try_get_path_from_dotnet_root(
const pal_char_t* dotnet_root,
/*out*/ pal_char_t** out_fxr_path);

#ifdef __cplusplus
}
#endif
// Try to find an already-loaded hostfxr in the current process. On success
// returns true, sets *out_fxr to the library handle and *out_fxr_path to a
// heap-allocated path. Caller should free() out_fxr_path.
bool fxr_resolver_try_get_existing_fxr(
/*out*/ pal_dll_t* out_fxr,
/*out*/ pal_char_t** out_fxr_path);

#ifdef __cplusplus

#include "hostfxr.h"
#include "trace.h"
#include "utils.h"
#include "error_codes.h"

namespace fxr_resolver
{
// Keep in sync with DotNetRootOptions.SearchLocation in HostWriter.cs
enum search_location : uint8_t
{
search_location_default = fxr_search_location_default,
search_location_app_local = fxr_search_location_app_local,
search_location_app_relative = fxr_search_location_app_relative,
search_location_environment_variable = fxr_search_location_environment_variable,
search_location_global = fxr_search_location_global,
};

bool try_get_path(const pal::string_t& root_path, pal::string_t* out_dotnet_root, pal::string_t* out_fxr_path);
bool try_get_path(const pal::string_t& root_path, search_location search, /*opt*/ pal::string_t* embedded_dotnet_root, pal::string_t* out_dotnet_root, pal::string_t* out_fxr_path);
bool try_get_path_from_dotnet_root(const pal::string_t& dotnet_root, pal::string_t* out_fxr_path);
bool try_get_existing_fxr(pal::dll_t *out_fxr, pal::string_t *out_fxr_path);
}

template<typename THostPathToConfigCallback, typename TBeforeRunCallback>
int load_fxr_and_get_delegate(hostfxr_delegate_type type, THostPathToConfigCallback host_path_to_config_path, TBeforeRunCallback on_before_run, void** delegate, bool try_ignore_missing_config)
{
pal::dll_t fxr;

pal::string_t host_path;
if (!pal::get_own_module_path(&host_path) || !pal::fullpath(&host_path))
{
trace::error(_X("Failed to resolve full path of the current host module [%s]"), host_path.c_str());
return StatusCode::CurrentHostFindFailure;
}

pal::string_t dotnet_root;
pal::string_t fxr_path;
if (fxr_resolver::try_get_existing_fxr(&fxr, &fxr_path))
{
dotnet_root = get_dotnet_root_from_fxr_path(fxr_path);
trace::verbose(_X("The library %s was already loaded. Reusing the previously loaded library [%s]."), LIBFXR_NAME, fxr_path.c_str());
}
else
{
// Do not specify the root path. Getting a delegate does not support self-contained (app-local fxr)
if (!fxr_resolver::try_get_path(pal::string_t{}, &dotnet_root, &fxr_path))
{
return StatusCode::CoreHostLibMissingFailure;
}

// We should always be loading hostfxr from an absolute path
if (!pal::is_path_fully_qualified(fxr_path))
return StatusCode::CoreHostLibMissingFailure;

// Load library
if (!pal::load_library(&fxr_path, &fxr))
{
trace::error(_X("The library %s was found, but loading it from %s failed"), LIBFXR_NAME, fxr_path.c_str());
return StatusCode::CoreHostLibLoadFailure;
}
}

// Leak fxr

auto hostfxr_initialize_for_runtime_config = reinterpret_cast<hostfxr_initialize_for_runtime_config_fn>(pal::get_symbol(fxr, "hostfxr_initialize_for_runtime_config"));
auto hostfxr_get_runtime_delegate = reinterpret_cast<hostfxr_get_runtime_delegate_fn>(pal::get_symbol(fxr, "hostfxr_get_runtime_delegate"));
auto hostfxr_close = reinterpret_cast<hostfxr_close_fn>(pal::get_symbol(fxr, "hostfxr_close"));
if (hostfxr_initialize_for_runtime_config == nullptr || hostfxr_get_runtime_delegate == nullptr || hostfxr_close == nullptr)
return StatusCode::CoreHostEntryPointFailure;

pal::string_t config_path;
pal::hresult_t status = host_path_to_config_path(host_path, &config_path);
if (status != StatusCode::Success)
return status;

hostfxr_set_error_writer_fn set_error_writer_fn = reinterpret_cast<hostfxr_set_error_writer_fn>(pal::get_symbol(fxr, "hostfxr_set_error_writer"));
{
propagate_error_writer_t propagate_error_writer_to_hostfxr(set_error_writer_fn);
if (!try_ignore_missing_config || pal::file_exists(config_path))
{
hostfxr_initialize_parameters parameters {
sizeof(hostfxr_initialize_parameters),
host_path.c_str(),
dotnet_root.c_str()
};

hostfxr_handle context;
int rc = hostfxr_initialize_for_runtime_config(config_path.c_str(), &parameters, &context);
if (!STATUS_CODE_SUCCEEDED(rc))
return rc;

on_before_run(fxr, context);

rc = hostfxr_get_runtime_delegate(context, type, delegate);

int rcClose = hostfxr_close(context);
if (rcClose != StatusCode::Success)
{
assert(false && "Failed to close host context");
trace::verbose(_X("Failed to close host context: 0x%x"), rcClose);
}

return rc;
}
else
{
// null context means use the current one, if none exists it will fail
int rc = hostfxr_get_runtime_delegate(nullptr, type, delegate);
if (rc == StatusCode::HostInvalidState)
{
trace::error(_X("Expected active runtime context because runtimeconfig.json [%s] does not exist."), config_path.c_str());
}
return rc;
}
}
}

#endif // __cplusplus
#endif

#endif //_COREHOST_CLI_FXR_RESOLVER_H_
Loading
Loading