diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/Pointer.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/Pointer.cs index 098ddfdcebaff1..ef8e82a9b0f18f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/Pointer.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/Pointer.cs @@ -39,6 +39,18 @@ public static object Box(void* ptr, Type type) return ((Pointer)ptr)._ptr; } + public override unsafe bool Equals(object? obj) + { + if (obj is Pointer pointer) + { + return _ptr == pointer._ptr; + } + + return false; + } + + public override unsafe int GetHashCode() => ((nuint)_ptr).GetHashCode(); + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { throw new PlatformNotSupportedException(); diff --git a/src/libraries/System.Reflection/tests/PointerTests.cs b/src/libraries/System.Reflection/tests/PointerTests.cs new file mode 100644 index 00000000000000..cbcf7828df59ce --- /dev/null +++ b/src/libraries/System.Reflection/tests/PointerTests.cs @@ -0,0 +1,136 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Xunit; +using System.Reflection; + +namespace System.Reflection.Tests +{ + public class PointerTests + { + public unsafe struct BitwiseComparable + { + public int* PublicInt; + } + + public unsafe struct MemberwiseComparable + { + public string ReferenceType; + public int* PublicInt; + } + + [Fact] + public unsafe void EqualBitwiseComparables_AreEqual() + { + int someNumber = 1; + var a = new BitwiseComparable(); + a.PublicInt = &someNumber; + BitwiseComparable b = a; + + Assert.True(a.Equals(b)); + Assert.Equal(a.GetHashCode(), b.GetHashCode()); + } + + [Fact] + public unsafe void UnequalBitwiseComparables_AreUnequal() + { + int someNumber = 1; + var a = new BitwiseComparable(); + a.PublicInt = &someNumber; + var b = new BitwiseComparable(); + + Assert.False(a.Equals(b)); + } + + [Fact] + public unsafe void SameBitwiseComparable_EqualWithSelf() + { + int someNumber = 1; + var a = new BitwiseComparable(); + a.PublicInt = &someNumber; + + Assert.True(a.Equals(a)); + } + + [Fact] + public unsafe void EqualMemberwiseComparables_AreEqual() + { + int someNumber = 1; + var a = new MemberwiseComparable(); + a.PublicInt = &someNumber; + MemberwiseComparable b = a; + + Assert.True(a.Equals(b)); + Assert.Equal(a.GetHashCode(), b.GetHashCode()); + } + + [Fact] + public unsafe void UnequalMemberwiseComparables_AreUnequal() + { + int someNumber = 1; + var a = new MemberwiseComparable(); + a.PublicInt = &someNumber; + var b = new MemberwiseComparable(); + + Assert.False(a.Equals(b)); + } + + [Fact] + public unsafe void SameMemberwiseComparable_EqualWithSelf() + { + int someNumber = 1; + var a = new MemberwiseComparable(); + a.PublicInt = &someNumber; + + Assert.True(a.Equals(a)); + } + + [Fact] + public unsafe void EqualPointers_AreEqual() + { + object a = Pointer.Box((void*)0x12340000, typeof(int*)); + object b = Pointer.Box((void*)0x12340000, typeof(int*)); + + Assert.True(a.Equals(b)); + Assert.Equal(a.GetHashCode(), b.GetHashCode()); + } + + [Fact] + public unsafe void Nullptrs_AreEqual() + { + object a = Pointer.Box(null, typeof(int*)); + object b = Pointer.Box(null, typeof(int*)); + + Assert.True(a.Equals(b)); + Assert.Equal(a.GetHashCode(), b.GetHashCode()); + } + + [Fact] + public unsafe void DifferentPointerTypes_AreEqual() + { + object a = Pointer.Box((void*)0x12340000, typeof(int*)); + object b = Pointer.Box((void*)0x12340000, typeof(uint*)); + + Assert.True(a.Equals(b)); + Assert.Equal(a.GetHashCode(), b.GetHashCode()); + } + + [Fact] + public unsafe void DifferentPointers_AreUnequal() + { + object a = Pointer.Box((void*)0x12340000, typeof(int*)); + object b = Pointer.Box((void*)0x56780000, typeof(int*)); + + Assert.False(a.Equals(b)); + } + + [Fact] + public unsafe void DifferentPointerTypes_Null_AreEqual() + { + object a = Pointer.Box(null, typeof(int*)); + object b = Pointer.Box(null, typeof(long*)); + + Assert.True(a.Equals(b)); + } + } +} diff --git a/src/libraries/System.Reflection/tests/System.Reflection.Tests.csproj b/src/libraries/System.Reflection/tests/System.Reflection.Tests.csproj index 3d22e60dfd35c5..f480b9783c53d9 100644 --- a/src/libraries/System.Reflection/tests/System.Reflection.Tests.csproj +++ b/src/libraries/System.Reflection/tests/System.Reflection.Tests.csproj @@ -30,6 +30,7 @@ + diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 2a0a3921bee9e7..7a44865a21f3ce 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -8551,6 +8551,8 @@ internal Pointer() { } public unsafe static object Box(void* ptr, System.Type type) { throw null; } void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } public unsafe static void* Unbox(object ptr) { throw null; } + public override bool Equals(object? obj) { throw null; } + public override int GetHashCode() { throw null; } } [System.FlagsAttribute] public enum PortableExecutableKinds