-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Make Runtime=NET task host handshake architecture-agnostic #13890
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ViktorHofer
wants to merge
3
commits into
dotnet:main
Choose a base branch
from
ViktorHofer:vihofer/fix-arm64-net-task-host-handshake
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
95 changes: 95 additions & 0 deletions
95
src/Build.UnitTests/BackEnd/CommunicationsUtilities_Tests.cs
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using Microsoft.Build.Framework; | ||
| using Microsoft.Build.Internal; | ||
| using Microsoft.Build.Shared; | ||
| using Shouldly; | ||
| using Xunit; | ||
|
|
||
| namespace Microsoft.Build.Engine.UnitTests.BackEnd | ||
| { | ||
| /// <summary> | ||
| /// Tests for <see cref="CommunicationsUtilities.GetHandshakeOptions"/> covering the parent | ||
| /// side of NET task host launches: the parent must suppress its own architecture bit on | ||
| /// the wire so already-shipped SDK children (whose <c>IsAllowedBitnessMismatch</c> tolerates | ||
| /// "parent sent no arch bit") accept the connection regardless of either process arch. | ||
| /// </summary> | ||
| public sealed class CommunicationsUtilities_Tests | ||
| { | ||
| [Theory] | ||
| [InlineData(XMakeAttributes.MSBuildArchitectureValues.x64)] | ||
| [InlineData(XMakeAttributes.MSBuildArchitectureValues.arm64)] | ||
| [InlineData(XMakeAttributes.MSBuildArchitectureValues.x86)] | ||
| public void GetHandshakeOptions_NetTaskHostParent_SuppressesArchBit(string parentArchitecture) | ||
| { | ||
| var parameters = new TaskHostParameters( | ||
| runtime: XMakeAttributes.MSBuildRuntimeValues.net, | ||
| architecture: parentArchitecture); | ||
|
|
||
| HandshakeOptions options = CommunicationsUtilities.GetHandshakeOptions( | ||
| taskHost: true, | ||
| taskHostParameters: parameters); | ||
|
|
||
| options.HasFlag(HandshakeOptions.NET).ShouldBeTrue(); | ||
| options.HasFlag(HandshakeOptions.X64).ShouldBeFalse(); | ||
| options.HasFlag(HandshakeOptions.Arm64).ShouldBeFalse(); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void GetHandshakeOptions_NonNetTaskHostParent_KeepsX64ArchBit() | ||
| { | ||
| var parameters = new TaskHostParameters( | ||
| runtime: XMakeAttributes.MSBuildRuntimeValues.clr4, | ||
| architecture: XMakeAttributes.MSBuildArchitectureValues.x64); | ||
|
|
||
| HandshakeOptions options = CommunicationsUtilities.GetHandshakeOptions( | ||
| taskHost: true, | ||
| taskHostParameters: parameters); | ||
|
|
||
| options.HasFlag(HandshakeOptions.X64).ShouldBeTrue(); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void GetHandshakeOptions_NonNetTaskHostParent_KeepsArm64ArchBit() | ||
| { | ||
| var parameters = new TaskHostParameters( | ||
| runtime: XMakeAttributes.MSBuildRuntimeValues.clr4, | ||
| architecture: XMakeAttributes.MSBuildArchitectureValues.arm64); | ||
|
|
||
| HandshakeOptions options = CommunicationsUtilities.GetHandshakeOptions( | ||
| taskHost: true, | ||
| taskHostParameters: parameters); | ||
|
|
||
| options.HasFlag(HandshakeOptions.Arm64).ShouldBeTrue(); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void GetHandshakeOptions_NetTaskHostChild_KeepsArchBit() | ||
| { | ||
| // The child invokes GetHandshakeOptions with TaskHostParameters.Empty; the helper | ||
| // then derives architectureFlagToSet from GetCurrentMSBuildArchitecture(). The | ||
| // suppression must not apply: the child needs to keep its own arch bit so | ||
| // already-deployed parents that still emit one continue to match. | ||
| HandshakeOptions options = CommunicationsUtilities.GetHandshakeOptions( | ||
| taskHost: true, | ||
| taskHostParameters: TaskHostParameters.Empty); | ||
|
|
||
| string currentArch = XMakeAttributes.GetCurrentMSBuildArchitecture(); | ||
| if (currentArch.Equals(XMakeAttributes.MSBuildArchitectureValues.x64, System.StringComparison.OrdinalIgnoreCase)) | ||
| { | ||
| options.HasFlag(HandshakeOptions.X64).ShouldBeTrue(); | ||
| } | ||
| else if (currentArch.Equals(XMakeAttributes.MSBuildArchitectureValues.arm64, System.StringComparison.OrdinalIgnoreCase)) | ||
| { | ||
| options.HasFlag(HandshakeOptions.Arm64).ShouldBeTrue(); | ||
| } | ||
| else | ||
| { | ||
| // x86 or unknown: no arch bit is expected on the child side either. | ||
| options.HasFlag(HandshakeOptions.X64).ShouldBeFalse(); | ||
| options.HasFlag(HandshakeOptions.Arm64).ShouldBeFalse(); | ||
| } | ||
| } | ||
| } | ||
| } |
77 changes: 77 additions & 0 deletions
77
src/Build.UnitTests/BackEnd/NodeEndpointOutOfProcBase_Tests.cs
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| #if NET | ||
|
|
||
| using Microsoft.Build.BackEnd; | ||
| using Microsoft.Build.Internal; | ||
| using Shouldly; | ||
| using Xunit; | ||
|
|
||
| namespace Microsoft.Build.Engine.UnitTests.BackEnd | ||
| { | ||
| /// <summary> | ||
| /// Tests for <see cref="NodeEndpointOutOfProcBase.IsAllowedBitnessMismatch"/>, the .NET task | ||
| /// host child-side tolerance that lets a parent which did not emit an architecture bit | ||
| /// (e.g. a .NET Framework MSBuild) connect to an SDK child running on x64 or arm64. | ||
| /// </summary> | ||
| public sealed class NodeEndpointOutOfProcBase_Tests | ||
| { | ||
| private const HandshakeOptions BaseNet = HandshakeOptions.TaskHost | HandshakeOptions.NET; | ||
|
|
||
| [Fact] | ||
| public void NoArchBitParent_X64Child_IsTolerated() | ||
| { | ||
| NodeEndpointOutOfProcBase.IsAllowedBitnessMismatch( | ||
| expectedOptions: (int)(BaseNet | HandshakeOptions.X64), | ||
| receivedOptions: (int)BaseNet).ShouldBeTrue(); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void NoArchBitParent_Arm64Child_IsTolerated() | ||
| { | ||
| NodeEndpointOutOfProcBase.IsAllowedBitnessMismatch( | ||
| expectedOptions: (int)(BaseNet | HandshakeOptions.Arm64), | ||
| receivedOptions: (int)BaseNet).ShouldBeTrue(); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void X64Parent_X64Child_NotConsideredMismatch() | ||
| { | ||
| // Equal handshakes never hit IsAllowedBitnessMismatch in production; verify it | ||
| // still returns false so the tolerance is scoped to the no-arch-bit parent only. | ||
| NodeEndpointOutOfProcBase.IsAllowedBitnessMismatch( | ||
| expectedOptions: (int)(BaseNet | HandshakeOptions.X64), | ||
| receivedOptions: (int)(BaseNet | HandshakeOptions.X64)).ShouldBeFalse(); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void X64Parent_Arm64Child_NotTolerated() | ||
| { | ||
| // True architecture mismatch (parent sent X64, child expects Arm64) is rejected. | ||
| NodeEndpointOutOfProcBase.IsAllowedBitnessMismatch( | ||
| expectedOptions: (int)(BaseNet | HandshakeOptions.Arm64), | ||
| receivedOptions: (int)(BaseNet | HandshakeOptions.X64)).ShouldBeFalse(); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void Arm64Parent_X64Child_NotTolerated() | ||
| { | ||
| NodeEndpointOutOfProcBase.IsAllowedBitnessMismatch( | ||
| expectedOptions: (int)(BaseNet | HandshakeOptions.X64), | ||
| receivedOptions: (int)(BaseNet | HandshakeOptions.Arm64)).ShouldBeFalse(); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void NoArchBitParent_NoArchBitChild_NotTolerated() | ||
| { | ||
| // The tolerance is scoped to x64/arm64 children; an x86-equivalent (no arch bit) | ||
| // child must not silently accept any handshake. | ||
| NodeEndpointOutOfProcBase.IsAllowedBitnessMismatch( | ||
| expectedOptions: (int)BaseNet, | ||
| receivedOptions: (int)BaseNet).ShouldBeFalse(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #endif | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -580,7 +580,25 @@ internal static HandshakeOptions GetHandshakeOptions( | |
| } | ||
| } | ||
|
|
||
| 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 | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't get this comment, what future? |
||
| // process architecture. Emitting the parent's arch bit here creates a wire-level | ||
| // mismatch with already-shipped SDK children whose arch differs (e.g. arm64 VS | ||
| // launching an x64 SDK MSBuild.dll). Suppress the arch bit so the child's existing | ||
| // IsAllowedBitnessMismatch tolerance ("parent sent no arch bit") accepts the | ||
| // connection regardless of either side's process architecture. | ||
| // | ||
| // Only the parent suppresses — i.e. when GetHandshakeOptions is invoked with concrete | ||
| // taskHostParameters describing a specific runtime/architecture to launch. The child | ||
| // (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 = | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this whole connection decision tree would greatly benefit from a flowchart/visualizations in docs |
||
| taskHost && | ||
| !taskHostParameters.IsEmpty && | ||
| XMakeAttributes.MSBuildRuntimeValues.net.Equals(taskHostParameters.Runtime, StringComparison.OrdinalIgnoreCase); | ||
|
|
||
| if (!isNetTaskHostParent && !string.IsNullOrEmpty(architectureFlagToSet)) | ||
| { | ||
| if (architectureFlagToSet!.Equals(XMakeAttributes.MSBuildArchitectureValues.x64, StringComparison.OrdinalIgnoreCase)) | ||
| { | ||
|
|
||
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
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.