Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

SentinelMethod.Equals should return reference equality#34380

Closed
benaadams wants to merge 1 commit intodotnet:masterfrom
benaadams:SentinelMethod-is-null
Closed

SentinelMethod.Equals should return reference equality#34380
benaadams wants to merge 1 commit intodotnet:masterfrom
benaadams:SentinelMethod-is-null

Conversation

@benaadams
Copy link
Copy Markdown
Member

@benaadams benaadams commented Jan 5, 2019

Seen in #34375 (comment)

Unhandled Exception of Type System.NullReferenceException
Message :
System.NullReferenceException : Object reference not set to an instance of an object.

   at System.Reflection.TypeLoading.Sentinels.SentinelMethod.Equals(Object obj) in D:\j\workspace\windows-TGrou---33cbf18b\src\System.Reflection.MetadataLoadContext\src\System\Reflection\TypeLoading\General\Sentinels.cs:line 36
   at System.Reflection.TypeLoading.RoEvent.GetRoAddMethod() in D:\j\workspace\windows-TGrou---33cbf18b\src\System.Reflection.MetadataLoadContext\src\System\Reflection\TypeLoading\Events\RoEvent.cs:line 58
   at System.Reflection.TypeLoading.RoEvent.GetAddMethod(Boolean nonPublic) in D:\j\workspace\windows-TGrou---33cbf18b\src\System.Reflection.MetadataLoadContext\src\System\Reflection\TypeLoading\Events\RoEvent.cs:line 62
   at System.Reflection.Tests.EventTests.EventTest1() in D:\j\workspace\windows-TGrou---33cbf18b\src\System.Reflection.MetadataLoadContext\tests\src\Tests\Event\EventTests.cs:line 27

Blocking update of coreclr update in corefx

With "Support faster null checks" dotnet/coreclr#21765 the .Equals override gets called so it should test since its overriden (or not be overriden); rather than just throw null

/cc @steveharter @jkotas @stephentoub

@benaadams benaadams changed the title SentinelMethod is a concrete null so its equals should behave as such SentinelMethod equals should reference check Jan 5, 2019
@benaadams benaadams force-pushed the SentinelMethod-is-null branch from 10ece32 to 6848d0b Compare January 5, 2019 13:04
@benaadams benaadams changed the title SentinelMethod equals should reference check SentinelMethod.Equals should return reference equality Jan 5, 2019
Copy link
Copy Markdown
Member

@stephentoub stephentoub left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are all of these overrides needed at all?

@jkotas
Copy link
Copy Markdown
Member

jkotas commented Jan 5, 2019

Why are all of these overrides needed at all?

Ati liked to write code this way. It is trying to ensure that somebody is not calling methods on the sentinel by accident, etc.

@jkotas
Copy link
Copy Markdown
Member

jkotas commented Jan 5, 2019

I am wondering whether this is an early red flag that the CoreCLR operator == changes are breaking. What are the chances that random custom reflection object models are going to have Equals broken in various ways?

I think the operator== changes should be fixed to keep calling left.Equals(right) like before. Yes, the code may be a bit bigger or slower but that is ok. (This change would not be necessary with this fix.)

@stephentoub
Copy link
Copy Markdown
Member

It is trying to ensure that somebody is not calling methods on the sentinel by accident, etc.

If the instance is exposed, though, which it would seem to be given the break (?), that seems like something that should be fixed so that the methods do something reasonable if they are used. Throwing a null ref isn't particularly friendly. At the very least they should throw not supported or something like that, no?

@jkotas
Copy link
Copy Markdown
Member

jkotas commented Jan 5, 2019

I think the operator== changes should be fixed to keep calling left.Equals(right) like before.

Or maybe abandon the idea of trying to "fix" operator == for null altogether, and go with the original plan to just use is null where the operator == gets used by accident.

@jkotas
Copy link
Copy Markdown
Member

jkotas commented Jan 5, 2019

Throwing a null ref isn't particularly friendly. At the very least they should throw not supported or something like that, no?

It depends on style you prefer. My style would be to have these safety overrides in debug build only with asserts, and not compile them into release at all.

@benaadams
Copy link
Copy Markdown
Member Author

Can still fix it for == null; but would need to double null check before calling left.Equals(right) which then makes it chunkier for the non == null due to the force inline

@benaadams
Copy link
Copy Markdown
Member Author

benaadams commented Jan 5, 2019

Also isn't having a broken .Equals override method and expecting operator== to work an odd assumption?

@stephentoub
Copy link
Copy Markdown
Member

My style would be to have these safety overrides in debug build only with asserts, and not compile them into release at all.

That sounds fine to me.

@stephentoub stephentoub closed this Jan 5, 2019
@stephentoub stephentoub reopened this Jan 5, 2019
@benaadams
Copy link
Copy Markdown
Member Author

My style would be to have these safety overrides in debug build only with asserts, and not compile them into release at all.

They are abstract method implementations which makes that trickier :-/

@benaadams
Copy link
Copy Markdown
Member Author

Not sure what next steps are here?

@benaadams
Copy link
Copy Markdown
Member Author

e.g. could change the checks to

public static bool operator ==(MethodInfo left, MethodInfo right)
{
    // Test "right" first to allow branch elimination when inlined for null checks (== null)
    // so it can become a simple test
    if (right is null)
    {
        return (left is null) ? true : false;
    }

    if (ReferenceEquals(left, right))
    {
        return true;
    }

    return (left is null) ? false : left.Equals(right);
}

@jkotas
Copy link
Copy Markdown
Member

jkotas commented Jan 6, 2019

Yes, I think that would work. Also, I would change ReferenceEquals to (object)left == (object)right. It is more friendly to the inliner - now that the method is marked with aggresive inlining.

@benaadams
Copy link
Copy Markdown
Member Author

dotnet/coreclr#21829

@benaadams
Copy link
Copy Markdown
Member Author

Going to close this one

@benaadams benaadams closed this Jan 6, 2019
@benaadams benaadams deleted the SentinelMethod-is-null branch January 11, 2019 21:35
@karelz karelz added this to the 3.0 milestone Mar 18, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants