Skip to content

Fix hostfxr resolution failure on musl when HOSTFXR_PATH is not set#55270

Merged
mthalman merged 6 commits into
dotnet:mainfrom
mthalman:mthalman-fix-dnx-musl-hostfxr-path
Jul 16, 2026
Merged

Fix hostfxr resolution failure on musl when HOSTFXR_PATH is not set#55270
mthalman merged 6 commits into
dotnet:mainfrom
mthalman:mthalman-fix-dnx-musl-hostfxr-path

Conversation

@mthalman

Copy link
Copy Markdown
Member

Symptoms

On musl-based distros (e.g. Alpine), running the SDK crashes with HostFxrRuntimePropertyNotSetException. It surfaced through dnx --help (exit 134), but dnx is only one trigger — not the actual bug. The same crash happens on any path that reaches the NativeWrapper hostfxr resolver on musl without HOSTFXR_PATH set. glibc is unaffected.

Root cause

The NativeWrapper hostfxr resolver depends on the host publishing the HOSTFXR_PATH runtime property; when it's absent, it falls back to a bare dlopen("hostfxr"). On glibc that bare load succeeds; on musl it fails, so the resolver throws.

HOSTFXR_PATH is only published when the SDK runs as a first-class SDK command — not when it's launched as an app via dotnet exec dotnet.dll <command>. dnx does exactly that, but this is a fundamental gap in the resolver, not something specific to dnx.

Fix

When HOSTFXR_PATH is not set, locate the highest-versioned hostfxr under <dotnet root>/host/fxr/<version>/ and load it explicitly. Version selection parses the numeric core of prerelease directory names (e.g. 11.0.0-preview.6..., which System.Version can't parse), prefers stable over prerelease of the same major version, and orders prerelease segments numerically (preview.10 after preview.6).

The logic previously existed — with the same latent bug — in both the NativeWrapper resolver and the Native AOT dn host. It's now extracted into a single source-shared src/Common/HostFxrPathResolver.cs compiled into both, so they can't diverge.

Fixes #55238

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
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
2 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.


[TestMethod]
public void ResolveHostfxrPath_SkipsPrereleaseDirectories()
public void ResolveHostfxrPath_FindsPrereleaseVersionDirectory()

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewers: Note this change in behavior. It wasn't clear to me that skipping prerelease versions was intentional or just a bug that AI created a test case to match its behavior. So I'm proposing that prerelease versions be handled.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting catch - I think it's reasonable to support preview versions of hostfxr, but I think it might be most-compatible if the hostfxr location took the 'allow prerelease' setting into account, via:

Actually, it might be best to align with the way the runtime locates hostfxr - @elinor-fung do you know how/when the runtime will look for preview hostfxrs?

@mthalman mthalman Jul 15, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked the native host's get_latest_fxr implementation: it allows prerelease versions and selects the highest valid SemVer. Neither DOTNET_ROLL_FORWARD_TO_PRERELEASE nor sdk.allowPrerelease affects hostfxr selection. I updated the fallback to use NuGet.Versioning.SemanticVersion and retain that behavior in c38bdd3.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome, thanks for doing that!

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses a musl-specific crash when the SDK is invoked via dotnet exec dotnet.dll <command> (e.g., dnx), where the host does not publish the HOSTFXR_PATH runtime property. The fix adds a filesystem-based fallback to locate and load the highest-versioned hostfxr from <dotnetRoot>/host/fxr/<version>/, and source-shares the version-selection logic so the NativeWrapper resolver and the Native AOT dn host cannot diverge.

Changes:

  • Add a fallback in Microsoft.DotNet.NativeWrapper to locate hostfxr under the running .NET root when HOSTFXR_PATH is missing, instead of crashing on musl.
  • Extract and source-share hostfxr path/version selection into src/Common/HostFxrPathResolver.cs, used by both NativeWrapper and dn.
  • Add/extend unit coverage for prerelease directory parsing and numeric prerelease segment ordering (e.g. preview.10 > preview.6).

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated no comments.

Show a summary per file
File Description
test/dotnet-aot.Tests/HostFxrLocatorTests.cs Adds unit tests for NativeWrapper’s hostfxr fallback locator, including musl/prerelease scenarios.
test/dotnet-aot.Tests/DotnetRootResolverTests.cs Updates/extends tests to validate prerelease hostfxr directory selection and numeric prerelease ordering.
src/Resolvers/Microsoft.DotNet.NativeWrapper/Microsoft.DotNet.NativeWrapper.csproj Source-includes shared resolver logic and exposes internals to dotnet-aot.Tests for testing.
src/Resolvers/Microsoft.DotNet.NativeWrapper/Interop.cs Uses the fallback locator when HOSTFXR_PATH is absent, preventing musl crashes.
src/Resolvers/Microsoft.DotNet.NativeWrapper/HostFxrLocator.cs Introduces NativeWrapper entry point that delegates to the shared resolver logic.
src/Common/HostFxrPathResolver.cs Implements shared hostfxr path resolution + version/prerelease ordering rules.
src/Cli/dn/DotnetRootResolver.cs Replaces local hostfxr resolution logic with the shared resolver implementation.
src/Cli/dn/dn.csproj Source-includes the shared hostfxr resolver logic into the AOT dn host build.

mthalman and others added 4 commits July 14, 2026 12:37
MSBuildSdkResolver source-globs the entire NativeWrapper tree, which now
references the shared HostFxrPathResolver type in src/Common. That file is
outside the glob, so add it to the project's existing src/Common includes to
fix the net472 CS0234 compile break.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d75dbb68-3527-49b4-9af6-d64469b45708
Mirror the native host's version parsing and precedence when selecting the latest hostfxr directory. Valid prerelease versions remain eligible, build metadata does not affect precedence, and malformed SemVer directories are ignored.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: d75dbb68-3527-49b4-9af6-d64469b45708
Replace the custom hostfxr version parser with NuGet's strict SemanticVersion implementation. Keep the fallback and dependency on modern .NET targets because the net472 resolver does not execute this code path.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: d75dbb68-3527-49b4-9af6-d64469b45708
Comment thread src/Cli/dn/dn.csproj
@mthalman
mthalman enabled auto-merge (squash) July 15, 2026 19:22
@mthalman
mthalman disabled auto-merge July 16, 2026 15:16
@mthalman
mthalman merged commit 6e6c854 into dotnet:main Jul 16, 2026
24 of 27 checks passed
@mthalman
mthalman deleted the mthalman-fix-dnx-musl-hostfxr-path branch July 16, 2026 15:17
@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 11.0-preview7 milestone Jul 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dnx crashes with on Alpine/musl because direct dotnet.dll invocation lacks HOSTFXR_PATH

5 participants