Skip to content
Merged
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
4 changes: 4 additions & 0 deletions docs/design/features/host-runtime-information.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ List of directory paths to search for managed assemblies. Paths are delimited by

List of directory paths corresponding to shared store paths and additional probing paths used by the host for [probing paths](./host-probing.md#probing-paths). Paths are delimited by a [platform-specific path separator](#path-separator).

`SYSTEM_CORELIB_DIRECTORY`

Absolute path to the directory containing `System.Private.CoreLib.dll`. When set, the runtime loads `System.Private.CoreLib` from this directory instead of looking for it beside `coreclr`. This is intended for hosts where `System.Private.CoreLib.dll` is not placed alongside `coreclr`. For hosts providing an assembly probe extension, a valid probe result takes precedence over this property. Otherwise, when this property is set, no fallback search is performed - if the file cannot be loaded from the specified directory, startup fails. Host is only allowed to specify directory since the runtime expects corelib to always be called `System.Private.CoreLib.dll`.

### Single-file

`BUNDLE_EXTRACTION_PATH`
Expand Down
16 changes: 15 additions & 1 deletion src/coreclr/binder/assemblybindercommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "failurecache.hpp"
#include "utils.hpp"
#include "stringarraylist.h"
#include "hostinformation.h"

#if !defined(DACCESS_COMPILE)
#include "defaultassemblybinder.h"
Expand Down Expand Up @@ -271,6 +272,9 @@ namespace BINDER_SPACE
// * Non-single-file app: In systemDirectory, beside coreclr.dll
// * Framework-dependent single-file app: In systemDirectory, beside coreclr.dll
// * Self-contained single-file app: Within the single-file bundle.
// * Host explicitly provided directory: In the directory set via the
// SYSTEM_CORELIB_DIRECTORY runtime property. Used by hosts where SPCL is not located
// in the same directory as coreclr.
//
// CoreLib path (sCoreLib):
// * Absolute path when looking for a file on disk
Expand All @@ -284,7 +288,16 @@ namespace BINDER_SPACE
{
pathSource = BinderTracing::PathSource::ApplicationAssemblies;
}
sCoreLib.Set(systemDirectory);

// Check for a host-provided explicit directory for CoreLib. When set, this replaces
// the default lookup beside coreclr and the bundle extraction path fallback.
bool hasHostProvidedDirectory = HostInformation::GetProperty(HOST_PROPERTY_SYSTEM_CORELIB_DIRECTORY, sCoreLib)
Comment thread
AaronRobinsonMSFT marked this conversation as resolved.
&& !sCoreLib.IsEmpty();
if (!hasHostProvidedDirectory)
{
sCoreLib.Set(systemDirectory);
}

CombinePath(sCoreLib, sCoreLibName, sCoreLib);

hr = AssemblyBinderCommon::GetAssembly(sCoreLib,
Expand All @@ -295,6 +308,7 @@ namespace BINDER_SPACE
BinderTracing::PathProbed(sCoreLib, pathSource, hr);

if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
&& !hasHostProvidedDirectory
Comment thread
elinor-fung marked this conversation as resolved.
&& Bundle::AppIsBundle()
&& Bundle::AppBundle->HasExtractedFiles())
{
Expand Down
18 changes: 18 additions & 0 deletions src/coreclr/hosts/corerun/corerun.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,24 @@ size_t HOST_CONTRACT_CALLTYPE get_runtime_property(
return len;
}

// Look up user-defined properties passed to corerun via -p/--property.
assert(config->user_defined_keys.size() == config->user_defined_values.size());
pal::string_t key_native = pal::convert_from_utf8(key);
for (size_t i = 0; i < config->user_defined_keys.size(); ++i)
{
if (config->user_defined_keys[i] == key_native)
{
pal::string_utf8_t value_utf8 = pal::convert_to_utf8(config->user_defined_values[i].c_str());
size_t len = value_utf8.size() + 1;
if (value_buffer_size < len)
return len;

::strncpy(value_buffer, value_utf8.c_str(), len - 1);
value_buffer[len - 1] = '\0';
return len;
}
}

return -1;
}

Expand Down
1 change: 1 addition & 0 deletions src/native/corehost/host_runtime_contract.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#define HOST_PROPERTY_NATIVE_DLL_SEARCH_DIRECTORIES "NATIVE_DLL_SEARCH_DIRECTORIES"
#define HOST_PROPERTY_PINVOKE_OVERRIDE "PINVOKE_OVERRIDE"
#define HOST_PROPERTY_PLATFORM_RESOURCE_ROOTS "PLATFORM_RESOURCE_ROOTS"
#define HOST_PROPERTY_SYSTEM_CORELIB_DIRECTORY "SYSTEM_CORELIB_DIRECTORY"
#define HOST_PROPERTY_TRUSTED_PLATFORM_ASSEMBLIES "TRUSTED_PLATFORM_ASSEMBLIES"

// Context passed to get_native_code_data callback
Expand Down
37 changes: 37 additions & 0 deletions src/tests/Loader/SystemCoreLibDirectory/SystemCoreLibDirectory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.IO;
using Xunit;

public class SystemCoreLibDirectory
{
[ConditionalFact(typeof(TestLibrary.Utilities), nameof(TestLibrary.Utilities.HasAssemblyFiles))]
public static void HostProvidedPath()
{
string configuredDirectory = AppContext.GetData("SYSTEM_CORELIB_DIRECTORY") as string;
Assert.False(string.IsNullOrEmpty(configuredDirectory), "SYSTEM_CORELIB_DIRECTORY should be set by the test harness");
Assert.True(Directory.Exists(configuredDirectory), $"SYSTEM_CORELIB_DIRECTORY should reference an existing directory: '{configuredDirectory}'");

string spclLocation = Path.GetFullPath(typeof(object).Assembly.Location);
string expectedLocation = Path.GetFullPath(Path.Combine(configuredDirectory, "System.Private.CoreLib.dll"));

StringComparison comparison = OperatingSystem.IsWindows()
? StringComparison.OrdinalIgnoreCase
: StringComparison.Ordinal;

Assert.True(
string.Equals(spclLocation, expectedLocation, comparison),
$"SPCL should be loaded from '{expectedLocation}', but was loaded from '{spclLocation}'");

string coreRoot = Environment.GetEnvironmentVariable("CORE_ROOT");
if (!string.IsNullOrEmpty(coreRoot))
{
string defaultPath = Path.Combine(coreRoot, "System.Private.CoreLib.dll");
Assert.False(
string.Equals(spclLocation, Path.GetFullPath(defaultPath), comparison),
$"SPCL should not be loaded from the default location beside coreclr: '{defaultPath}'");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RequiresProcessIsolation>true</RequiresProcessIsolation>
<NativeAotIncompatible>true</NativeAotIncompatible>
<!-- This test exercises the CoreCLR system assembly binder -->
<CLRTestTargetUnsupported Condition="'$(RuntimeFlavor)' != 'coreclr'">true</CLRTestTargetUnsupported>
</PropertyGroup>
<ItemGroup>
<Compile Include="SystemCoreLibDirectory.cs" />

<ProjectReference Include="$(TestLibraryProjectPath)" />

<!-- Point the runtime at the Subdirectory created by the pre-commands below to look for
System.Private.CoreLib.dll. The %25cd%25 / $%28pwd) tokens expand at script execution
time to the test working directory. -->
<RuntimeHostConfigurationOption Include="SYSTEM_CORELIB_DIRECTORY"
Value="%25cd%25\Subdirectory"
Condition="'$(TestWrapperTargetsWindows)' == 'true'" />
<RuntimeHostConfigurationOption Include="SYSTEM_CORELIB_DIRECTORY"
Value="$%28pwd)/Subdirectory"
Condition="'$(TestWrapperTargetsWindows)' != 'true'" />
</ItemGroup>
<PropertyGroup>
<CoreLibSetupBatch><![CDATA[
mkdir Subdirectory
copy /Y "%CORE_ROOT%\System.Private.CoreLib.dll" "Subdirectory\"
]]></CoreLibSetupBatch>
<CoreLibSetupBash><![CDATA[
mkdir -p Subdirectory
cp "$CORE_ROOT/System.Private.CoreLib.dll" "Subdirectory/"
]]></CoreLibSetupBash>
<CLRTestBatchPreCommands>$(CLRTestBatchPreCommands);$(CoreLibSetupBatch)</CLRTestBatchPreCommands>
<CLRTestBashPreCommands>$(CLRTestBashPreCommands);$(CoreLibSetupBash)</CLRTestBashPreCommands>
</PropertyGroup>
</Project>
Loading