Make Runtime=NET task host handshake architecture-agnostic#13890
Make Runtime=NET task host handshake architecture-agnostic#13890ViktorHofer wants to merge 3 commits into
Conversation
IsAllowedBitnessMismatch is the .NET task host child-side relaxation that lets a parent without an architecture bit on the wire (typically a .NET Framework MSBuild) connect to an SDK child that runs on x64. On Windows-ARM the SDK child runs as arm64 instead, but the function only considered expectedIsX64, so any arm64 child rejected the connection -> the launch times out and Runtime="NET" tasks fail with MSB4216. Also tolerate expectedIsArm64. True cross-arch mismatches (parent X64 vs child Arm64, or vice versa) remain rejected. Make the method internal static so the test project can exercise the tolerance matrix directly. The previous instance method did not touch any instance state. Partial fix for dotnet#13879 (Bug A). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Fixes a child-side handshake check that prevented .NET Framework MSBuild parents from launching a Runtime="NET" task host on Windows-ARM. IsAllowedBitnessMismatch previously only tolerated an x64-expecting child when the parent sent no architecture bit; it now tolerates arm64-expecting children as well, while still rejecting true cross-arch mismatches (X64↔Arm64). The method is also promoted to internal static to make it directly unit-testable.
Changes:
- Extend
IsAllowedBitnessMismatchto acceptexpectedIsArm64in addition toexpectedIsX64. - Convert the method to
internal staticand refresh its doc comment. - Add unit tests covering the no-arch-bit-parent tolerance matrix (x64/arm64 child) and rejection of true cross-arch mismatches.
Show a summary per file
| File | Description |
|---|---|
| src/Shared/NodeEndpointOutOfProcBase.cs | Tolerate arm64-expecting child in bitness mismatch check; expose as internal static; update XML doc. |
| src/Build.UnitTests/BackEnd/NodeEndpointOutOfProcBase_Tests.cs | New #if NET tests for the tolerance matrix and cross-arch rejection. |
Copilot's findings
- Files reviewed: 2/2 changed files
- Comments generated: 0
There was a problem hiding this comment.
Review Summary — PR #13890
Well-scoped bug fix extending the .NET task host handshake tolerance to arm64 children. The logic change is correct and the approach is sound.
Findings
| # | Dimension | Severity | Summary |
|---|---|---|---|
| 1 | Test Coverage & Completeness | MODERATE | Missing test for "no-arch parent → no-arch child" (the path where receivedIsX86==true but method returns false) |
| 2 | Documentation Accuracy | NIT | Inherited mask comment has version/flags description inverted |
Clean Dimensions (22/24)
Backwards Compatibility ✓ · ChangeWave ✓ · Performance ✓ · Error Messages ✓ · Logging ✓ · String Comparison ✓ · API Surface ✓ · Target Authoring ✓ · Design ✓ · Cross-Platform ✓ · Code Simplification ✓ · Concurrency ✓ · Naming ✓ · SDK Integration ✓ · Idiomatic C# ✓ · File I/O ✓ · Build Infrastructure ✓ · Scope & PR Discipline ✓ · Evaluation Model ✓ · Correctness ✓ · Dependency Mgmt ✓ · Security ✓
Notes
- The
private → internal staticvisibility change is appropriate for testability; the class is alreadyinternaland the method is a pure stateless predicate. - The behavioral change is strictly a relaxation (accepts arm64 where previously only x64 was accepted), so no ChangeWave is needed.
- The fix correctly rejects true cross-arch mismatches (e.g., parent declares X64 but child expects Arm64).
Note
🔒 Integrity filter blocked 2 items
The following items were blocked because they don't meet the GitHub integrity level.
- #13890
pull_request_read: has lower integrity than agent requires. The agent cannot read data with integrity below "approved". - #13890
pull_request_read: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".
To allow these resources, lower min-integrity in your GitHub frontmatter:
tools:
github:
min-integrity: approved # merged | approved | unapproved | noneGenerated by Expert Code Review (on open) for issue #13890 · ● 5.5M
For NET task host launches the child process's architecture is determined by what the .NET SDK shipped (x64 today, arm64 in the future), not by the parent's process architecture. Emitting the parent's arch bit creates a wire-level mismatch with already-shipped SDK children whose arch differs (e.g. arm64 VS launching an x64 SDK MSBuild.dll, or amd64 VS launching an arm64 SDK MSBuild.dll). The existing child-side IsAllowedBitnessMismatch tolerance only accepts "parent sent no arch bit", so this currently fails with MSB4216. In CommunicationsUtilities.GetHandshakeOptions, suppress the X64/Arm64 bit when invoked by the parent for a NET task host (detected by Runtime="net" in the explicit TaskHostParameters). The child path (TaskHostParameters .Empty) is unaffected so already-deployed parents that still emit an arch bit continue to match. Combined with the child-side Arm64 tolerance in this PR, every parent/ child architecture combination now connects against every already-shipped SDK that has the original (x64-only) tolerance. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add NoArchBitParent_NoArchBitChild_NotTolerated test (catches a regression that would simplify the return to just receivedIsX86). - Fix inverted comment on the 0x00FFFFFF mask (lower 24 bits are flags, upper byte is version). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
|
||
| if (!string.IsNullOrEmpty(architectureFlagToSet)) | ||
| // For the NET task host, the launched child process's architecture is determined by | ||
| // what the .NET SDK shipped (x64 today, arm64 in the future), not by the parent's |
There was a problem hiding this comment.
I don't get this comment, what future?
| // (which calls GetHandshakeOptions with TaskHostParameters.Empty) keeps its own arch | ||
| // bit so that already-deployed parents that still emit an arch bit continue to match | ||
| // (or fall through to IsAllowedBitnessMismatch's tolerance). | ||
| bool isNetTaskHostParent = |
There was a problem hiding this comment.
this whole connection decision tree would greatly benefit from a flowchart/visualizations in docs
|
@rainersigwald it would be great if you could also take a look :) Just want to be careful. |
Summary
Runtime="NET"task host launches fail withMSB4216whenever the parent and child architectures don't line up the way the original implementation expected. Tracked as #13879 (Bug A).Two coordinated handshake changes — one on each side — close every reasonable parent/child arch combination:
1. Parent side —
CommunicationsUtilities.GetHandshakeOptionsFor NET task host the launched child process's architecture is whatever the .NET SDK shipped (x64 today, arm64 in the future), not the parent's. Emitting the parent's arch bit produces a wire-level mismatch with already-shipped SDK children whose arch differs.
Suppress the
X64/Arm64bit when invoked by the parent for a NET task host (detected byRuntime="net"in the explicitTaskHostParameters). The child path (TaskHostParameters.Empty) is unaffected, so already-deployed parents that still emit an arch bit continue to match against new children.2. Child side —
NodeEndpointOutOfProcBase.IsAllowedBitnessMismatchThe .NET task host child-side relaxation that lets a parent without an arch bit on the wire connect to an SDK child. Previously only tolerated
expected = X64, so any arm64 SDK child rejected the connection. Now also toleratesexpected = Arm64. True cross-arch mismatches (parentX64↔ childArm64) remain rejected.Method is promoted to
internal staticso the test project can exercise the tolerance matrix directly. It was a stateless pure predicate already.Effect across parent / SDK combinations
current= behavior with this PR applied (parent change in VS MSBuild, child change in a future SDK). For each combo, "current behavior" notes whether the SDK side needs to update.expectedIsX64tolerance)expectedIsArm64toleranceWhere each fix takes effect
expectedIsX64tolerance already covers the child)The reported binlog (Roslyn build on Windows-ARM, SDK 10.0.108, x86 VS 18 MSBuild parent) is the first row — needs the SDK side to pick this up.
Tests
src/Build.UnitTests/BackEnd/NodeEndpointOutOfProcBase_Tests.cs(6 cases):NoArchBitParent_X64Child_IsToleratedNoArchBitParent_Arm64Child_IsToleratedX64Parent_X64Child_NotConsideredMismatchX64Parent_Arm64Child_NotToleratedArm64Parent_X64Child_NotToleratedNoArchBitParent_NoArchBitChild_NotTolerated(guards against a future simplification toreturn receivedIsX86;)src/Build.UnitTests/BackEnd/CommunicationsUtilities_Tests.cs(5 cases):GetHandshakeOptions_NetTaskHostParent_SuppressesArchBit× { x64, arm64, x86 }GetHandshakeOptions_NonNetTaskHostParent_KeepsX64ArchBitGetHandshakeOptions_NonNetTaskHostParent_KeepsArm64ArchBitGetHandshakeOptions_NetTaskHostChild_KeepsArchBitAll 11 pass on net10.0.
References