Skip to content

Commit

Permalink
Merge pull request #23727 from sharwell/checksum-compat
Browse files Browse the repository at this point in the history
Avoid depending on sizeof(T) for ExplicitLayout types due to Mono bug
  • Loading branch information
sharwell authored Dec 12, 2017
2 parents 5429b35 + 35a4b1d commit 1634419
Showing 1 changed file with 23 additions and 4 deletions.
27 changes: 23 additions & 4 deletions src/Workspaces/Core/Portable/Workspace/Solution/Checksum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ namespace Microsoft.CodeAnalysis
/// </summary>
internal sealed partial class Checksum : IObjectWritable, IEquatable<Checksum>
{
/// <summary>
/// The intended size of the <see cref="Sha1Hash"/> structure. Some runtime environments are known to deviate
/// from this size, so the implementation code should remain functionally correct even when the structure size
/// is greater than this value.
/// </summary>
/// <seealso href="https://bugzilla.xamarin.com/show_bug.cgi?id=60298">LayoutKind.Explicit, Size = 12 ignored with 64bit alignment</seealso>
/// <seealso href="https://github.com/dotnet/roslyn/issues/23722">Checksum throws on Mono 64-bit</seealso>
private const int Sha1HashSize = 20;

public static readonly Checksum Null = new Checksum(Array.Empty<byte>());

private Sha1Hash _checkSum;
Expand All @@ -25,14 +34,15 @@ public unsafe Checksum(byte[] checksum)
_checkSum = default;
return;
}
else if (checksum.Length != sizeof(Sha1Hash))
else if (checksum.Length != Sha1HashSize)
{
throw new ArgumentException($"{nameof(checksum)} must be a SHA-1 hash", nameof(checksum));
}

fixed (byte* data = checksum)
{
_checkSum = *(Sha1Hash*)data;
// Avoid a direct dereferencing assignment since sizeof(Sha1Hash) may be greater than Sha1HashSize.
_checkSum = Sha1Hash.FromPointer((Sha1Hash*)data);
}
}

Expand Down Expand Up @@ -65,7 +75,7 @@ public override unsafe string ToString()
*(Sha1Hash*)dataPtr = _checkSum;
}

return Convert.ToBase64String(data);
return Convert.ToBase64String(data, 0, Sha1HashSize);
}

public static bool operator ==(Checksum left, Checksum right)
Expand Down Expand Up @@ -98,7 +108,7 @@ public static string GetChecksumsLogInfo(IEnumerable<Checksum> checksums)
/// This structure stores the 20-byte SHA 1 hash as an inline value rather than requiring the use of
/// <c>byte[]</c>.
/// </summary>
[StructLayout(LayoutKind.Explicit, Size = 20)]
[StructLayout(LayoutKind.Explicit, Size = Sha1HashSize)]
private struct Sha1Hash : IEquatable<Sha1Hash>
{
[FieldOffset(0)]
Expand All @@ -123,6 +133,15 @@ public void WriteTo(ObjectWriter writer)
writer.WriteInt32(Data3);
}

public static unsafe Sha1Hash FromPointer(Sha1Hash* hash)
{
Sha1Hash result = default;
result.Data1 = hash->Data1;
result.Data2 = hash->Data2;
result.Data3 = hash->Data3;
return result;
}

public static Sha1Hash ReadFrom(ObjectReader reader)
{
Sha1Hash result = default;
Expand Down

0 comments on commit 1634419

Please sign in to comment.