diff --git a/src/coreclr/dlls/mscoree/exports.cpp b/src/coreclr/dlls/mscoree/exports.cpp index e8ee88275df8eb..7cf1f629a6027c 100644 --- a/src/coreclr/dlls/mscoree/exports.cpp +++ b/src/coreclr/dlls/mscoree/exports.cpp @@ -19,6 +19,8 @@ #endif // FEATURE_GDBJIT #include "bundle.h" #include "pinvokeoverride.h" +#include +#include #define ASSERTE_ALL_BUILDS(expr) _ASSERTE_ALL_BUILDS((expr)) @@ -122,7 +124,8 @@ static void ConvertConfigPropertiesToUnicode( LPCWSTR** propertyValuesWRef, BundleProbeFn** bundleProbe, PInvokeOverrideFn** pinvokeOverride, - bool* hostPolicyEmbedded) + bool* hostPolicyEmbedded, + host_runtime_contract** hostContract) { LPCWSTR* propertyKeysW = new (nothrow) LPCWSTR[propertyCount]; ASSERTE_ALL_BUILDS(propertyKeysW != nullptr); @@ -139,7 +142,8 @@ static void ConvertConfigPropertiesToUnicode( { // If this application is a single-file bundle, the bundle-probe callback // is passed in as the value of "BUNDLE_PROBE" property (encoded as a string). - *bundleProbe = (BundleProbeFn*)_wcstoui64(propertyValuesW[propertyIndex], nullptr, 0); + if (*bundleProbe == nullptr) + *bundleProbe = (BundleProbeFn*)_wcstoui64(propertyValuesW[propertyIndex], nullptr, 0); } else if (strcmp(propertyKeys[propertyIndex], "PINVOKE_OVERRIDE") == 0) { @@ -152,6 +156,14 @@ static void ConvertConfigPropertiesToUnicode( // The HOSTPOLICY_EMBEDDED property indicates if the executable has hostpolicy statically linked in *hostPolicyEmbedded = (wcscmp(propertyValuesW[propertyIndex], W("true")) == 0); } + else if (strcmp(propertyKeys[propertyIndex], HOST_PROPERTY_RUNTIME_CONTRACT) == 0) + { + // Host contract is passed in as the value of HOST_RUNTIME_CONTRACT property (encoded as a string). + host_runtime_contract* hostContractLocal = (host_runtime_contract*)_wcstoui64(propertyValuesW[propertyIndex], nullptr, 0); + *hostContract = hostContractLocal; + if (hostContractLocal->bundle_probe != nullptr) + *bundleProbe = hostContractLocal->bundle_probe; + } } *propertyKeysWRef = propertyKeysW; @@ -196,6 +208,7 @@ int coreclr_initialize( BundleProbeFn* bundleProbe = nullptr; bool hostPolicyEmbedded = false; PInvokeOverrideFn* pinvokeOverride = nullptr; + host_runtime_contract* hostContract = nullptr; ConvertConfigPropertiesToUnicode( propertyKeys, @@ -205,7 +218,8 @@ int coreclr_initialize( &propertyValuesW, &bundleProbe, &pinvokeOverride, - &hostPolicyEmbedded); + &hostPolicyEmbedded, + &hostContract); #ifdef TARGET_UNIX DWORD error = PAL_InitializeCoreCLR(exePath, g_coreclr_embedded); @@ -221,7 +235,12 @@ int coreclr_initialize( g_hostpolicy_embedded = hostPolicyEmbedded; - if (pinvokeOverride != nullptr) + if (hostContract != nullptr) + { + HostInformation::SetContract(hostContract); + } + + if (pinvokeOverride != nullptr && (hostContract == nullptr || hostContract->pinvoke_override == nullptr)) { PInvokeOverride::SetPInvokeOverride(pinvokeOverride, PInvokeOverride::Source::RuntimeConfiguration); } diff --git a/src/coreclr/inc/hostinformation.h b/src/coreclr/inc/hostinformation.h new file mode 100644 index 00000000000000..d57b4729d30e68 --- /dev/null +++ b/src/coreclr/inc/hostinformation.h @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#ifndef _HOSTINFORMATION_H_ +#define _HOSTINFORMATION_H_ + +#include + +class HostInformation +{ +public: + static void SetContract(_In_ host_runtime_contract* hostContract); + static bool GetProperty(_In_z_ const char* name, SString& value); +}; + +#endif // _HOSTINFORMATION_H_ diff --git a/src/coreclr/vm/CMakeLists.txt b/src/coreclr/vm/CMakeLists.txt index 68169ccb4edea2..7d7826b5a0d70a 100644 --- a/src/coreclr/vm/CMakeLists.txt +++ b/src/coreclr/vm/CMakeLists.txt @@ -328,6 +328,7 @@ set(VM_SOURCES_WKS genanalysis.cpp genmeth.cpp hosting.cpp + hostinformation.cpp ilmarshalers.cpp interopconverter.cpp interoputil.cpp diff --git a/src/coreclr/vm/hostinformation.cpp b/src/coreclr/vm/hostinformation.cpp new file mode 100644 index 00000000000000..6ad189290b71cc --- /dev/null +++ b/src/coreclr/vm/hostinformation.cpp @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "common.h" +#include "hostinformation.h" +#include "pinvokeoverride.h" + +namespace +{ + host_runtime_contract* s_hostContract = nullptr; +} + +void HostInformation::SetContract(_In_ host_runtime_contract* hostContract) +{ + _ASSERTE(s_hostContract == nullptr); + s_hostContract = hostContract; + + if (s_hostContract->pinvoke_override != nullptr) + PInvokeOverride::SetPInvokeOverride(s_hostContract->pinvoke_override, PInvokeOverride::Source::RuntimeConfiguration); +} + +bool HostInformation::GetProperty(_In_z_ const char* name, SString& value) +{ + if (s_hostContract == nullptr || s_hostContract->get_runtime_property == nullptr) + return false; + + size_t len = MAX_PATH + 1; + char* dest = value.OpenUTF8Buffer(static_cast(len)); + size_t lenActual = s_hostContract->get_runtime_property(name, dest, len, s_hostContract->context); + value.CloseBuffer(); + + // Doesn't exist or failed to get property + if (lenActual == (size_t)-1 || lenActual == 0) + return false; + + if (lenActual <= len) + return true; + + // Buffer was not large enough + len = lenActual; + dest = value.OpenUTF8Buffer(static_cast(len)); + lenActual = s_hostContract->get_runtime_property(name, dest, len, s_hostContract->context); + value.CloseBuffer(); + + return lenActual > 0 && lenActual <= len; +} diff --git a/src/native/corehost/host_runtime_contract.h b/src/native/corehost/host_runtime_contract.h new file mode 100644 index 00000000000000..ebdb5ab8427668 --- /dev/null +++ b/src/native/corehost/host_runtime_contract.h @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#ifndef __HOST_RUNTIME_CONTRACT_H__ +#define __HOST_RUNTIME_CONTRACT_H__ + +#include +#include + +#if defined(_WIN32) + #define HOST_CONTRACT_CALLTYPE __stdcall +#else + #define HOST_CONTRACT_CALLTYPE +#endif + +// Known host property names +#define HOST_PROPERTY_RUNTIME_CONTRACT "HOST_RUNTIME_CONTRACT" +#define HOST_PROPERTY_ENTRY_ASSEMBLY_NAME "ENTRY_ASSEMBLY_NAME" + +struct host_runtime_contract +{ + void* context; + + bool(HOST_CONTRACT_CALLTYPE* bundle_probe)( + const char* path, + int64_t* offset, + int64_t* size, + int64_t* compressedSize); + + const void* (HOST_CONTRACT_CALLTYPE* pinvoke_override)( + const char* library_name, + const char* entry_point_name); + + size_t(HOST_CONTRACT_CALLTYPE* get_runtime_property)( + const char* key, + char* value_buffer, + size_t value_buffer_size, + void* contract_context); +}; + +#endif // __HOST_RUNTIME_CONTRACT_H__ diff --git a/src/native/corehost/hostmisc/pal.h b/src/native/corehost/hostmisc/pal.h index 2af1dbd214fd66..dee5bf3c94d444 100644 --- a/src/native/corehost/hostmisc/pal.h +++ b/src/native/corehost/hostmisc/pal.h @@ -180,6 +180,7 @@ namespace pal return buffer; } + size_t pal_utf8string(const string_t& str, char* out_buffer, size_t len); bool pal_utf8string(const string_t& str, std::vector* out); bool pal_clrstring(const string_t& str, std::vector* out); bool clr_palstring(const char* cstr, string_t* out); @@ -236,6 +237,16 @@ namespace pal inline const string_t strerror(int errnum) { return ::strerror(errnum); } + inline size_t pal_utf8string(const string_t& str, char* out_buffer, size_t buffer_len) + { + size_t len = str.size() + 1; + if (buffer_len < len) + return len; + + ::strncpy(out_buffer, str.c_str(), str.size()); + out_buffer[len - 1] = '\0'; + return len; + } inline bool pal_utf8string(const string_t& str, std::vector* out) { out->assign(str.begin(), str.end()); out->push_back('\0'); return true; } inline bool pal_clrstring(const string_t& str, std::vector* out) { return pal_utf8string(str, out); } inline bool clr_palstring(const char* cstr, string_t* out) { out->assign(cstr); return true; } diff --git a/src/native/corehost/hostmisc/pal.windows.cpp b/src/native/corehost/hostmisc/pal.windows.cpp index bbb6fabb30b79f..4dd632ac88d336 100644 --- a/src/native/corehost/hostmisc/pal.windows.cpp +++ b/src/native/corehost/hostmisc/pal.windows.cpp @@ -689,6 +689,17 @@ static bool wchar_convert_helper(DWORD code_page, const char* cstr, size_t len, return ::MultiByteToWideChar(code_page, 0, cstr, static_cast(len), &(*out)[0], static_cast(out->size())) != 0; } +size_t pal::pal_utf8string(const pal::string_t& str, char* out_buffer, size_t len) +{ + // Pass -1 as we want explicit null termination in the char buffer. + size_t size = ::WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, nullptr, 0, nullptr, nullptr); + if (size == 0 || size > len) + return size; + + // Pass -1 as we want explicit null termination in the char buffer. + return ::WideCharToMultiByte(CP_UTF8, 0, str.c_str(), -1, out_buffer, static_cast(len), nullptr, nullptr); +} + bool pal::pal_utf8string(const pal::string_t& str, std::vector* out) { out->clear(); diff --git a/src/native/corehost/hostpolicy/hostpolicy_context.cpp b/src/native/corehost/hostpolicy/hostpolicy_context.cpp index e1cff0dc376efa..27f94f4e1c67bc 100644 --- a/src/native/corehost/hostpolicy/hostpolicy_context.cpp +++ b/src/native/corehost/hostpolicy/hostpolicy_context.cpp @@ -2,7 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. #include "hostpolicy_context.h" -#include "hostpolicy.h" +#include +#include #include "deps_resolver.h" #include @@ -104,6 +105,31 @@ namespace return nullptr; } #endif + + size_t HOST_CONTRACT_CALLTYPE get_runtime_property( + const char* key, + char* value_buffer, + size_t value_buffer_size, + void* contract_context) + { + hostpolicy_context_t* context = static_cast(contract_context); + if (::strcmp(key, HOST_PROPERTY_ENTRY_ASSEMBLY_NAME) == 0) + { + return pal::pal_utf8string(get_filename_without_ext(context->application), value_buffer, value_buffer_size); + } + + pal::string_t key_str; + if (pal::clr_palstring(key, &key_str)) + { + const pal::char_t* value; + if (context->coreclr_properties.try_get(key_str.c_str(), &value)) + { + return pal::pal_utf8string(value, value_buffer, value_buffer_size); + } + } + + return -1; + } } int hostpolicy_context_t::initialize(hostpolicy_init_t &hostpolicy_init, const arguments_t &args, bool enable_breadcrumbs) @@ -324,5 +350,25 @@ int hostpolicy_context_t::initialize(hostpolicy_init_t &hostpolicy_init, const a } #endif + { + host_contract = { this }; + if (bundle::info_t::is_single_file_bundle()) + { + host_contract.bundle_probe = &bundle_probe; +#if defined(NATIVE_LIBS_EMBEDDED) + host_contract.pinvoke_override = &pinvoke_override; +#endif + } + + host_contract.get_runtime_property = &get_runtime_property; + pal::stringstream_t ptr_stream; + ptr_stream << "0x" << std::hex << (size_t)(&host_contract); + if (!coreclr_properties.add(_STRINGIFY(HOST_PROPERTY_RUNTIME_CONTRACT), ptr_stream.str().c_str())) + { + log_duplicate_property_error(_STRINGIFY(HOST_PROPERTY_RUNTIME_CONTRACT)); + return StatusCode::LibHostDuplicateProperty; + } + } + return StatusCode::Success; } diff --git a/src/native/corehost/hostpolicy/hostpolicy_context.h b/src/native/corehost/hostpolicy/hostpolicy_context.h index 2853e6ae98fb16..bec4630762fe03 100644 --- a/src/native/corehost/hostpolicy/hostpolicy_context.h +++ b/src/native/corehost/hostpolicy/hostpolicy_context.h @@ -9,6 +9,7 @@ #include "args.h" #include "coreclr.h" #include +#include #include "hostpolicy_init.h" struct hostpolicy_context_t @@ -27,6 +28,8 @@ struct hostpolicy_context_t std::unique_ptr coreclr; + host_runtime_contract host_contract; + int initialize(hostpolicy_init_t &hostpolicy_init, const arguments_t &args, bool enable_breadcrumbs); };