From 007602d0ae3ddf88077015cea5662d2dc01cba1f Mon Sep 17 00:00:00 2001 From: Nathan Mytelka Date: Tue, 8 Sep 2020 16:23:19 -0700 Subject: [PATCH 1/3] Add StableStringHash method This method hashes a string without taking target framework or bitness into account. Fixes #4986 --- src/Build/Evaluation/Expander.cs | 8 ++++++++ src/Build/Evaluation/IntrinsicFunctions.cs | 8 ++++++++ src/Shared/CommunicationsUtilities.cs | 4 ++-- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/Build/Evaluation/Expander.cs b/src/Build/Evaluation/Expander.cs index cdbc45e9f47..d1c0642017e 100644 --- a/src/Build/Evaluation/Expander.cs +++ b/src/Build/Evaluation/Expander.cs @@ -4017,6 +4017,14 @@ private bool TryExecuteWellKnownFunction(out object returnVal, object objectInst return true; } } + else if (string.Equals(_methodMethodName, nameof(IntrinsicFunctions.StableStringHash), StringComparison.OrdinalIgnoreCase)) + { + if (TryGetArg(args, out string arg0)) + { + returnVal = IntrinsicFunctions.StableStringHash(arg0); + return true; + } + } } else if (_receiverType == typeof(Path)) { diff --git a/src/Build/Evaluation/IntrinsicFunctions.cs b/src/Build/Evaluation/IntrinsicFunctions.cs index d0143d1560d..920d54e4b5d 100644 --- a/src/Build/Evaluation/IntrinsicFunctions.cs +++ b/src/Build/Evaluation/IntrinsicFunctions.cs @@ -347,6 +347,14 @@ internal static string ValueOrDefault(string conditionValue, string defaultValue } } + /// + /// Hash the string independent of bitness and target framework. + /// + internal static int StableStringHash(string toHash) + { + return CommunicationsUtilities.GetHashCode(toHash); + } + /// /// Returns true if a task host exists that can service the requested runtime and architecture /// values, and false otherwise. diff --git a/src/Shared/CommunicationsUtilities.cs b/src/Shared/CommunicationsUtilities.cs index 6ef1da20e51..f8d13539acc 100644 --- a/src/Shared/CommunicationsUtilities.cs +++ b/src/Shared/CommunicationsUtilities.cs @@ -81,7 +81,7 @@ internal Handshake(HandshakeOptions nodeType) options = (int)nodeType | (((int)CommunicationsUtilities.handshakeVersion) << 24); string handshakeSalt = Environment.GetEnvironmentVariable("MSBUILDNODEHANDSHAKESALT"); string toolsDirectory = (nodeType & HandshakeOptions.X64) == HandshakeOptions.X64 ? BuildEnvironmentHelper.Instance.MSBuildToolsDirectory64 : BuildEnvironmentHelper.Instance.MSBuildToolsDirectory32; - salt = CommunicationsUtilities.GetHandshakeHashCode(handshakeSalt + toolsDirectory); + salt = CommunicationsUtilities.GetHashCode(handshakeSalt + toolsDirectory); Version fileVersion = new Version(FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion); fileVersionMajor = fileVersion.Major; fileVersionMinor = fileVersion.Minor; @@ -620,7 +620,7 @@ internal static void Trace(int nodeId, string format, params object[] args) /// but stripped out architecture specific defines /// that causes the hashcode to be different and this causes problem in cross-architecture handshaking /// - internal static int GetHandshakeHashCode(string fileVersion) + internal static int GetHashCode(string fileVersion) { unsafe { From a0bbd9342cf9c02d65de139ede1ce347d6813afd Mon Sep 17 00:00:00 2001 From: Nathan Mytelka Date: Tue, 8 Sep 2020 16:23:32 -0700 Subject: [PATCH 2/3] Test StableStringHash --- .../Evaluation/Expander_Tests.cs | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/Build.UnitTests/Evaluation/Expander_Tests.cs b/src/Build.UnitTests/Evaluation/Expander_Tests.cs index 536996904e0..9037ec537e0 100644 --- a/src/Build.UnitTests/Evaluation/Expander_Tests.cs +++ b/src/Build.UnitTests/Evaluation/Expander_Tests.cs @@ -3609,6 +3609,41 @@ public void PropertyStringConstructorConsumingItemMetadata(string metadatumName, result.ShouldBe(metadatumValue); } + [Fact] + public void PropertyFunctionHashCodeSameOnlyIfStringSame() + { + PropertyDictionary pg = new PropertyDictionary(); + Expander expander = new Expander(pg, FileSystems.Default); + string[] stringsToHash = { + "cat1s", + "cat1z", + "bat1s", + "cut1s", + "cat1so", + "cats1", + "acat1s", + "cat12s", + "cat1s" + }; + int[] hashes = stringsToHash.Select(toHash => + (int)expander.ExpandPropertiesLeaveTypedAndEscaped($"$([MSBuild]::StableStringHash('{toHash}'))", ExpanderOptions.ExpandProperties, MockElementLocation.Instance) + ).ToArray(); + for (int a = 0; a < hashes.Length; a++) + { + for (int b = a; b < hashes.Length; b++) + { + if (stringsToHash[a].Equals(stringsToHash[b])) + { + hashes[a].ShouldBe(hashes[b], "Identical strings should hash to the same value."); + } + else + { + hashes[a].ShouldNotBe(hashes[b], "Different strings should not hash to the same value."); + } + } + } + } + /// /// A whole bunch error check tests /// From 19cce71e8823e86097fc12db40f8edc6ebc41076 Mon Sep 17 00:00:00 2001 From: Forgind Date: Fri, 2 Oct 2020 11:51:51 -0700 Subject: [PATCH 3/3] Update src/Shared/CommunicationsUtilities.cs --- src/Shared/CommunicationsUtilities.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Shared/CommunicationsUtilities.cs b/src/Shared/CommunicationsUtilities.cs index b2540531477..3b0a98ea917 100644 --- a/src/Shared/CommunicationsUtilities.cs +++ b/src/Shared/CommunicationsUtilities.cs @@ -84,7 +84,6 @@ internal Handshake(HandshakeOptions nodeType) string toolsDirectory = (nodeType & HandshakeOptions.X64) == HandshakeOptions.X64 ? BuildEnvironmentHelper.Instance.MSBuildToolsDirectory64 : BuildEnvironmentHelper.Instance.MSBuildToolsDirectory32; CommunicationsUtilities.Trace("Tools directory is " + toolsDirectory); salt = CommunicationsUtilities.GetHashCode(handshakeSalt + toolsDirectory); - salt = CommunicationsUtilities.GetHandshakeHashCode(handshakeSalt + toolsDirectory); Version fileVersion = new Version(FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion); fileVersionMajor = fileVersion.Major; fileVersionMinor = fileVersion.Minor;