Two equal IPv6 IPAddress instances return different GetHashCode results
Asked Answered
A

1

15

I have two clients that create IPAddress instances from the same byte[] and send it to the server over WCF (using DataContractSerializer).

On the server, these IPAddress instances are inserted as keys in a dictionary but for some reason they're added as different keys.

When logging I see that they're equal but GetHashCode returns different results.

var client1Address = // sent from client1
var client2Address = // sent from client2

Console.WriteLine(client1Address.Equals(client2Address));
Console.WriteLine(client1Address.GetHashCode().Equals(client2Address.GetHashCode()));

Output:

true
false

How can equal IPAddress instances return different GetHashCode results?

Allseed answered 11/2, 2015 at 17:33 Comment(0)
A
16

The GetHashCode implementation of IPAddress for IPv6 is:

if (m_HashCode == 0)
{
    m_HashCode = StringComparer.InvariantCultureIgnoreCase.GetHashCode(ToString()); 
    return m_HashCode;
}

To avoid recalculating the hash code again and again, they’re storing the result in a private member. This private member is then serialized to the remote server.

The thing is, that StringComparer.InvariantCultureIgnoreCase.GetHashCode(ToString()) returns different results on different OS versions, and since m_HashCode is serialized as well, the server does not recalculate it.

This results in two identical IPAddress instances with different GetHashCode results.

I think that the private member m_HashCode should be marked as [NonSerialized], that will cause GetHashCode to re-generate the hash code locally and correctly.

As a workaround, I interfered in the serialization process and serialized as a byte[].


Here's the bug on VisualStudio connect. This link is dead as the bug was closed for these reasons:

"Thank you for reporting this issue. Unfortunately, our team is not able to address this issue due to other, higher priority items. Further, any changes to the serialized content of a type result in a risk of breaking apps that have taken a dependency on that behavior. "

Allseed answered 11/2, 2015 at 17:34 Comment(2)
I believe this exact scenario is warned about in .NET GetHashCode and String Compare and String based Equality operators. I do not think this is a bug in that GetHashCode is effectively a private .NET runtime property that should not be directly used by our code at an application level. Since IPV6 is a known thing I would use the address itself as the Hash Code or Equality operator. But I would do the actual compare at the byte level for a formatted value. Similar to how guid works. “ABCD-123” = “abcd123” From A Design Perspective I think it is a bug. Can they change it now?Tacket
@SqlSurfer GetHashCode isn't private and it isn't used directly. When you use IPAddress as a dictionary key it uses GetHashCode internally. The bug here is that the hash code is cached and serialized when it shouldn't be.Factotum

© 2022 - 2024 — McMap. All rights reserved.