Skip to content
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

Ensure that GetContentHash produces the same value on different endian machines #74696

Merged
merged 10 commits into from
Aug 9, 2024
23 changes: 21 additions & 2 deletions src/Compilers/Core/Portable/Text/SourceText.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// See the LICENSE file in the project root for more information.

using System;
using System.Buffers;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel;
Expand Down Expand Up @@ -642,7 +642,26 @@ ImmutableArray<byte> computeContentHash()
sourceIndex: index, destination: charBuffer,
destinationIndex: 0, count: charsToCopy);

hash.Append(MemoryMarshal.AsBytes(charBuffer.AsSpan(0, charsToCopy)));
var charSpan = charBuffer.AsSpan(0, charsToCopy);

// Ensure everything is always little endian, so we get the same results across all platforms.
// This will be entirely elided by the jit on a little endian machine.
if (!BitConverter.IsLittleEndian)
{
var shortSpan = MemoryMarshal.Cast<char, short>(charSpan);

#if NET8_0_OR_GREATER
// Defer to the platform to do the reversal. It ships with a vectorized
// implementation for this on .NET 8 and above.
BinaryPrimitives.ReverseEndianness(source: shortSpan, destination: shortSpan);
#else
// Otherwise, fallback to the simple approach of reversing each pair of bytes.
for (var i = 0; i < shortSpan.Length; i++)
shortSpan[i] = BinaryPrimitives.ReverseEndianness(shortSpan[i]);
#endif
}

hash.Append(MemoryMarshal.AsBytes(charSpan));
}

// Switch this to ImmutableCollectionsMarshal.AsImmutableArray(hash.GetHashAndReset()) when we move to S.C.I v8.
Expand Down