From 0d83a2289892d75daac3372aca0ff9b1c624e9dc Mon Sep 17 00:00:00 2001 From: Matt Thalman Date: Tue, 14 Jul 2026 08:54:47 -0500 Subject: [PATCH 1/4] Fix dnx crash on Alpine/musl by locating hostfxr under the .NET root When dnx runs via `dotnet exec dotnet.dll dnx`, the host treats it as an app launch rather than a first-class SDK command and omits the HOSTFXR_PATH runtime property. On musl the NativeWrapper hostfxr resolver then throws HostFxrRuntimePropertyNotSetException. Add a fallback that locates the hostfxr library under the .NET installation root. The resolution logic is shared via source (src/Common/HostFxrPathResolver.cs) between the NativeWrapper resolver and the Native AOT dn host so the two cannot diverge. It parses the numeric core of prerelease version directory names (e.g. 11.0.0-preview.6.26359.118), which System.Version cannot parse, prefers stable over prerelease of the same core, and orders prerelease segments numerically so preview.10 sorts after preview.6. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d75dbb68-3527-49b4-9af6-d64469b45708 --- src/Cli/dn/DotnetRootResolver.cs | 41 +-- src/Cli/dn/dn.csproj | 4 + src/Common/HostFxrPathResolver.cs | 140 ++++++++++ .../HostFxrLocator.cs | 51 ++++ .../Microsoft.DotNet.NativeWrapper/Interop.cs | 18 +- .../Microsoft.DotNet.NativeWrapper.csproj | 5 + .../DotnetRootResolverTests.cs | 71 ++++- test/dotnet-aot.Tests/HostFxrLocatorTests.cs | 242 ++++++++++++++++++ 8 files changed, 531 insertions(+), 41 deletions(-) create mode 100644 src/Common/HostFxrPathResolver.cs create mode 100644 src/Resolvers/Microsoft.DotNet.NativeWrapper/HostFxrLocator.cs create mode 100644 test/dotnet-aot.Tests/HostFxrLocatorTests.cs diff --git a/src/Cli/dn/DotnetRootResolver.cs b/src/Cli/dn/DotnetRootResolver.cs index f09f90504233..ef0696bcb47d 100644 --- a/src/Cli/dn/DotnetRootResolver.cs +++ b/src/Cli/dn/DotnetRootResolver.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.InteropServices; +using Microsoft.DotNet.HostFxr; namespace Microsoft.DotNet.Cli; @@ -84,37 +85,11 @@ internal static string ResolveHostfxrPath( Func directoryExists, Func getDirectories, Func fileExists) - { - string fxrDir = Path.Combine(dotnetRoot, "host", "fxr"); - if (!directoryExists(fxrDir)) - { - return string.Empty; - } - - // Pick the highest version directory by parsing version numbers - string? latestFxr = getDirectories(fxrDir) - .Select(path => new - { - Path = path, - Version = Version.TryParse(Path.GetFileName(path), out Version? version) ? version : null - }) - .Where(candidate => candidate.Version is not null) - .OrderByDescending(candidate => candidate.Version) - .Select(candidate => candidate.Path) - .FirstOrDefault(); - - if (latestFxr is null) - { - return string.Empty; - } - - string hostfxrName = isWindows - ? "hostfxr.dll" - : isMacOS - ? "libhostfxr.dylib" - : "libhostfxr.so"; - - string hostfxrPath = Path.Combine(latestFxr, hostfxrName); - return fileExists(hostfxrPath) ? hostfxrPath : string.Empty; - } + => HostFxrPathResolver.ResolveHostFxrPath( + dotnetRoot, + isWindows, + isMacOS, + directoryExists, + getDirectories, + fileExists); } diff --git a/src/Cli/dn/dn.csproj b/src/Cli/dn/dn.csproj index c969c489389e..c282de376b49 100644 --- a/src/Cli/dn/dn.csproj +++ b/src/Cli/dn/dn.csproj @@ -22,6 +22,10 @@ + + + +