GetHashCode weirdness

Sorry, got caught up in a big mess at the end of the week, so everything got halted. I am going to get back into it hopefully today or tomorrow. I have updated the proposals, with the Any overloads idea (which allows you to use the unmanaged and managed chaining systems with 'looser' constraints when you want to), and it works well. I also implement equality on ManagedChain to make them more similar to Tuple. However, I have encountered the wierdest bug ever in my GetHashCode implementation.
1 Reply
thargy
thargy3y ago
/// <inheritdoc />
/// <remarks>HashCodes do not need to be unique, so ww only sample the structure type and the start of each
/// structure's 'payload'.
public override int GetHashCode()
{
var ptr = HeadPtr;
var span = new ReadOnlySpan<byte>((void*) ptr, MemorySize);
var start = 0;
var length = HeadSize;
var sliceLength = length - HeaderSize;
var hashCode = 0;
// Hash the structure type
var sTYpe = (ptr + start)->SType;
hashCode = HashCode.Combine(hashCode, sTYpe);

// Hash any payload
if (sliceLength >= 0)
CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength));

start += length;
length = Item1Size;
sliceLength = length - HeaderSize;
sTYpe = (ptr + start)->SType;
hashCode = HashCode.Combine(hashCode, sTYpe);
if (sliceLength >= 0)
CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength));
return hashCode;
}
/// <inheritdoc />
/// <remarks>HashCodes do not need to be unique, so ww only sample the structure type and the start of each
/// structure's 'payload'.
public override int GetHashCode()
{
var ptr = HeadPtr;
var span = new ReadOnlySpan<byte>((void*) ptr, MemorySize);
var start = 0;
var length = HeadSize;
var sliceLength = length - HeaderSize;
var hashCode = 0;
// Hash the structure type
var sTYpe = (ptr + start)->SType;
hashCode = HashCode.Combine(hashCode, sTYpe);

// Hash any payload
if (sliceLength >= 0)
CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength));

start += length;
length = Item1Size;
sliceLength = length - HeaderSize;
sTYpe = (ptr + start)->SType;
hashCode = HashCode.Combine(hashCode, sTYpe);
if (sliceLength >= 0)
CombineHash(ref hashCode, span.Slice(start + HeaderSize, sliceLength));
return hashCode;
}
The problem is at the second sTYpe = (ptr + start)->SType; line (near the end). Which get's the SType for Item1. I have confirmed that ptr+start is indeed pointing to Item1Ptr position. AND that when accessing that memory location from the calling method it gets the correct SType every time (see TestManagedChain.TestManagedChainGetHashCode in PrototypStructChaining/TestManagedChain.cs - which has Assert.Equal(StructureType.PhysicalDeviceDescriptorIndexingFeatures, chain.Item1Ptr->SType); where Item1Ptr is identical to ptr+start above) Despite everything seeming equal, the test only succeeds occasionally (~1 in 7 times), so it's not even a constant fail! Obviously, the memory referenced isn't moving, so my current best guess is that the structures field orders are being mangled, however, that would break lots of other code, and carefully looking at the bytes directly, it doesn't look to be the issue. I'll probably rewrite the method entirely, as I have an alternate approach, but this bug is super weird