Repository navigation
fix(managed): admit ReadyToRun images built for non-Windows hosts - #1985
Merged
morluto merged 1 commit intoOct 12, 2026
Merged
Conversation
ReadyToRun images compiled for Linux, macOS or the BSDs store the COFF machine XORed with IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE (dotnet/runtime src/coreclr/inc/pedecoder.h). Every framework assembly in a Linux .NET install has machine 0xFD1D, so target admission and the managed PE reader rejected them as an unsupported architecture. Decode the PE machine once in src/domain/peMachine.ts, replacing the two duplicated switches, and accept an OS override only on images with a CLI directory.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
3 tasks done
Owner
|
@JayOfTheKeyboard, thanks for bringing the ReadyToRun OS-override machine decoding into one shared PE interpretation path. Your measurements against real .NET installations show why this matters in practice, and the coverage across Linux, Apple, and BSD encodings is especially helpful. Welcome to REA! |
Contributor
Author
|
Thank you, happy to be here! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
REA rejects every .NET ReadyToRun assembly compiled for Linux, macOS or the BSDs with
unsupported PE architecture. On a Linux .NET install that covers most of the shared framework, soinspect-artifactand all three managed inspection tools refuse files likeSystem.Private.CoreLib.dll. No issue is linked: I found this by running REA over the assemblies on my machine, and the fix is small enough to explain here.Problem and expected behavior
ReadyToRun images built for a non-Windows host do not store a plain COFF machine. The .NET toolchain XORs it with an OS constant,
IMAGE_FILE_MACHINE_NATIVE_OS_OVERRIDE, defined in dotnet/runtimesrc/coreclr/inc/pedecoder.h:0x7B790xFD1D0x46440xC0200xADC40x2BA00xADC50x2BA10x19930x9FF70x19920x9FF6parsePeRecordinsrc/domain/binaryTarget.tsandarchitectureForinsrc/dotnet/ManagedPeReader.tseach had their own switch over the five Windows machine values. Anything else was rejected before the CLI header was read.Measured on Fedora 44 with the distribution's .NET 8.0.31 SDK, on
mainat1d4c4eb0:/usr/lib64/dotnethave machine0xFD1D. That is 89 of the 168 inshared/Microsoft.NETCore.App(includingSystem.Private.CoreLib.dll), all 139 inshared/Microsoft.AspNetCore.App, and SDK assemblies such asMicrosoft.Build.Framework.dll. The other 2,027 are AnyCPU IL (0x014C).inspect-artifactandinspect-managed-memberseach failed on 9 andinspect-managed-native-boundarieson 7. Every failure was this bug.Expected: these are managed PE files, and REA should inspect their metadata the same way it does for a Windows build.
Change and scope
src/domain/peMachine.tsowns COFF machine decoding.decodePeMachinetries the plain value first, then the six documented overrides, and returns{ architecture, nativeOsOverride }. No override value decodes to a second valid machine, and none collides with a plain one.parsePeRecordandManagedPeReaderboth call it. Their duplicated switches are removed.0xFD1Dis still rejected, with the same error text as before.ManagedPeLayout.machinealready keeps the raw value, sope.machine_hexstill reports0xfd1d.Not changed, and yours to decide:
parsePeRecordneeds the architecture before it can find the data directories, so it cannot pass the managed flag into the decoder. Folding the guard into the decoder would mean reordering that function's header checks.Contract and boundary impact
src/domain/peMachine.ts), used byparsePeRecordandreadManagedPeLayout.format: "pe",managed: true. Windows machine values behave exactly as before.Evidence and regression coverage
Tests added or updated:
src/domain/binaryTarget.test.ts: x86_64 for all six hosts and arm64 for Linux and Apple, on a managed PE32+ header. Also checks that an override machine on a native image is still rejected.tests/boundary/providers/managed/managedNativeOsMachine.test.ts: Linux x86, Linux ARM, Apple ARM and FreeBSD x86 ReadyToRun fixtures go throughparseBinaryTargetand all three managed operations. Assertspe.machine,pe.architectureandmanaged_architecture.src/dotnet/ManagedArtifactFailures.test.ts: the managed reader rejects an override machine when the image has no CLI directory.Base reproduction: on the parent commit, the new header and boundary cases fail with
unsupported PE architecture. Mutations each turn at least one test red: removing either guard, skipping the override loop, or dropping any one of the six constants.User-visible CLI/MCP output, with the fix, on
System.Private.CoreLib.dll:Remaining proof gaps: no macOS, BSD or arm64 ReadyToRun binaries were run. Those cases are covered by fixtures only. Linux x64 was run against real files.
For evidence-bearing changes:
Validation performed
npm run test:focused --over everysrc/domainandsrc/dotnettest,tests/boundary/providers/managed/*,tests/acceptance/managedCliOutput.test.tsandtests/boundary/mcp/managedMcp.test.ts: 147 files, 2,172 tests passed.npm run check:fast: passed.npm run verify:test-discovery: "Discovered all 882 test files exactly once."0xFD1Dassemblies all succeed withinspect-managed-members. The 40-file random sample now passesinspect-artifact,inspect-managed-membersandinspect-managed-native-boundarieswith no failures from this cause.Compatibility, safety, and release
Review checklist
type(scope): outcome.