Skip to content

Behavior for pointer equality depends on its declaring struct. #42457

@Dimension4

Description

@Dimension4

Coming from this stackoverflow question, the equality of two pointers (e.g. int*) depends on the layout of the struct that declares said pointer. For example:

unsafe readonly struct S1
{
    public readonly int A1, A2;
    public readonly int* B;

    public S1(int a1, int a2, int* b)
    {
        A1 = a1;
        A2 = a2;
        B = b;
    }
}

int x = 10;
var a = new S1(1, 2, &x);
var b = new S1(1, 2, &x);

Equals(a, b)  // true

Here, two instances are equal, because a and b are compared with memcmp (bitwise comparison) which means that the address that B holds is compared (meaning comparison by value).

However, the following code

unsafe readonly struct S2
{
    public readonly int A1;
    public readonly int* B;

    public S1(int a1, int* b)
    {
        A1 = a1;
        B = b;
    }
}

int x = 10;
var a = new S2(1, &x);

Equals(a, b)  // false
Equals(a, a)  // false!

fails the equality test. This is because System.ValueType.CanCompareBits evaluates to false (probably because of memory padding, I couldn't verify, it's a compiler intrinsic) and ValueType falls back to comparing the structs via reflection. Getting the value of a pointer via reflection causes that pointer to be boxed into a System.Reflection.Pointer, which is a reference type that does not override Object.Equals. Therefore, S2.B is compared by reference equality, which always evaluates to false because the pointer has been boxed during reflection.

This has been tested on netcore 2.1, 3.0 and net 5.0.

It looks like System.Reflection.Pointer should override Equals and compare the addresses of the pointer (aka its value).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions