-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
JIT optimization breaks pointer/ref arithmetic #61510
Comments
Tagging subscribers to this area: @JulieLeeMSFT Issue DetailsDescriptionWe allocate some unmanaged memory that we then manipulate via references rather than raw pointers. We use the following trick to get a ref byte from an address stored as nint.
This works correctly in .NET 5, but returns a null pointer in .NET 6, where this code gets JITed to return 0 unconditionally, as follows:
Reproduction Steps
Expected behaviorThe JIT should output code performing arithmetic with the given parameter. Actual behaviorJIT outputs code returning 0 unconditionally. Regression?The example works correctly in .NET 5. Known WorkaroundsNo response Configuration.NET Version 6.0.100 Other informationNo response
|
Not related to the actual codegen issue, but... Wouldn't it be more compact and also easier to read to implement that public static unsafe ref byte M(nint p)
{
return ref *(byte*)p;
} L0000: mov rax, rcx
L0003: ret |
I went with |
Having fake "safe" code using APIs like this instead of properly using built-in unsafe syntax is objectively worse and should be avoided. It makes it harder to see when code is actually doing unsafe things. It effectively makes your code more unsafe. It's an ongoing problem that has been here forever, certainly not helped by the existence of some APIs (looking at you There was a good comment by @tannergooding with some guidance on this (or was it a Twitter thread?), can't find it now 😄 |
So the immediate cause of this is the following morph transform: runtime/src/coreclr/jit/morph.cpp Lines 12402 to 12423 in 35704e4
I do not know why this wasn't an issue in 5.0, this code is fairly ancient. There is a "bug in a bug" here: when we swap operands just above the quoted code, we may lose the GC-ness of a byref: Edit: I will take this then. |
Thanks @SingleAccretion for taking on this one. CC @dotnet/jit-contrib |
Description
We allocate some unmanaged memory that we then manipulate via references rather than raw pointers. We use the following trick to get a ref byte from an address stored as nint.
public static ref byte GetReference(nint addr) => ref Unsafe.AddByteOffset(ref Unsafe.NullRef<byte>(), addr);
This works correctly in .NET 5, but returns a null pointer in .NET 6, where this code gets JITed to return 0 unconditionally, as follows:
Reproduction Steps
Expected behavior
The JIT should output code performing arithmetic with the given parameter.
Actual behavior
JIT outputs code returning 0 unconditionally.
Regression?
The example works correctly in .NET 5.
Known Workarounds
No response
Configuration
.NET Version 6.0.100
Windows Version 10.0.19042 Build 19042
x64
Other information
No response
The text was updated successfully, but these errors were encountered: