-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Correctly handle use of cgt
and others for object refs (fixes #3465)
#3481
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Thanks! |
But is this correct? Is the JIT silently switching |
Looks like I rushed this a bit too much and didn't really read into it! ECMA says its only valid for null as implemented in ILSpy already and modern C# JIT appears to treat them as pointers (A quick glance at dotnet/runtime reveals no special handling of The current way of rewriting these comparisons on the IL level is incorrect. The only other alternative I see to decompile this properly would be to handle this case on the C# AST level or when translating ILAst to C# AST. Would this be appropriate, and if so, which way would be preferred? |
It's probably an obfuscator hiding nulls in static fields? Am I guessing correctly that I'm not sure what we should do about this, if anything. |
This is actually something I have not considered! It may very well be the case here, as it is something decently common in obfuscation. @greenozon, could you confirm? If this is, in fact, the case, we can close the PR and issue, I'd say, since it's not something the C# compiler will/has produced.
If this doesn't end up as an obfuscation issue, I think this is the way that makes the most sense. |
This is one way to do it. However, it depends on the memory layout of public static unsafe bool GreaterThan(object left, object right)
{
TypedReference leftTypedReference = __makeref(left);
void* leftPointer = **(void***)&leftTypedReference;
TypedReference rightTypedReference = __makeref(right);
void* rightPointer = **(void***)&rightTypedReference;
return leftPointer > rightPointer;
} |
Or maybe just this? It requires C# 11. public static unsafe bool GreaterThan(object left, object right)
{
return *(void**)&left > *(void**)&right;
} |
Yes, Both of these ideas have the problem of requiring an lvalue object pointer, so we'd need to avoid inlining in these cases; or un-inline later (via |
Actually there's no reason to use an unmanaged pointer for the second level of indirection. |
Link to issue(s) this covers
#3465
Problem
ILSpy did not handle use of
cgt
for object reference comparison where neither side wasldnull
.This is allowed as stated in ECMA:
"cgt.un is allowed and verifiable on ObjectRefs (O). This is commonly used when comparing an ObjectRef with null (there is no “compare-not-equal” instruction, which would otherwise be a more obvious solution)" - ECMA III.1.5 - Operand type table, Table III.4: Binary Comparison or Branch Operations, Note 2
Code checks for other comparison types just like it did before for
ldnull
but now for all object refs.Solution
@greenozon Could you verify if this changes fixes your issue on your file?