-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
Possible codegen issue with unbox instruction for nullable types #86203
Comments
Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch Issue DetailsDescriptionI encountered a bug when using the "unbox valuetype System.Nullable`1<!!0>" instruction. The bug causes the unboxed value to be incorrect. However, the bug is not always reproducible. It depends on some details of the code, such as the way of asserting the value and whether the AggressiveOptimization attribute is enabled or not. I suspect that the bug is related to some optimization mechanism in the code generation process, but I'm not sure how to debug it further. Here are the codes : .method public hidebysig static valuetype System.Nullable`1<!!T>&
UnboxNullable<valuetype .ctor (System.ValueType) T>(object boxed) cil managed {
.maxstack 8
ldarg.0
unbox valuetype System.Nullable`1<!!0>
ret
} or equivalently using InlineIL.Fody public static ref T? UnboxNullable<T>(object? boxed) where T : struct {
Emit.Ldarg(nameof(boxed));
Emit.Unbox(typeof(T?));
Emit.Ret();
throw null!;
} Reproduction StepsTo reproduce the bug, I used the following code: [Test()]
// [MethodImpl(MethodImplOptions.AggressiveOptimization)]
public static void UnboxNullableTest() {
var boxed = (object?)(int?)42;
ref var v = ref Unsafe.UnboxNullable<int>(boxed);
Assert.IsTrue(42 == v);
Assert.AreEqual(42, v);
} Expected behaviorThe test UnboxNullableTest should pass. Actual behaviorAssert failure. Regression?No response Known WorkaroundsNo response Configuration.NET 7.0.5 Other informationECMA-335 2012 p.431
|
I don't see how the highlighted ECMA paragraph proves it's not correct. It doesn't say anything about boxing an integer and unboxing it as nullable (via unbox, not unbox.any) You boxed a 4-byte integer and obtained an address of the boxed contet as a 8-byte struct |
@EgorBo As I understand it, first, boxing an |
Yes, via
Do you mean a pointer to the stack of |
Although, the ECMA says: 🤔 Does it say that cc @jkotas |
Via
Oh, I think I see where the problem is. Unless there is some mechanism that ensures UnboxNullable is inlined or supported as an intrinsic, it seems that this form of the library function won't work, because the copied struct's lifetime is implicitly and naturally expected to cover at least the scope of the unbox instruction, and when the library function returns, that struct can be destroyed. Although theoretically the implementation could make a real copy on the GC heap, that would not be efficient, nor required by ECMA-335. |
@EgorBo Do you think copying to the GC heap is a requirement of ECMA-335? I just thought that was a possible way to do it. |
RyuJIT implements We can either document the current behavior in the ECMA augments or change the codegen to allocate the storage on GC heap as the ECMA spec suggests. If we choose to do the later, we need to do analysis of affected places - changing the stack allocation to GC heap allocation can be a significant regression. I have a mild preference for documenting the current behavior by saying that unbox is not supported for |
Description
I encountered a bug when using the "unbox valuetype System.Nullable`1<!!0>" instruction. The bug causes the unboxed value to be incorrect.
However, the bug is not always reproducible. It depends on some details of the code, such as the way of asserting the value and whether the AggressiveOptimization attribute is enabled or not.
I suspect that the bug is related to some optimization mechanism in the code generation process, but I'm not sure how to debug it further.
Here are the codes :
or equivalently using InlineIL.Fody
Reproduction Steps
To reproduce the bug, I used the following code:
Expected behavior
The test UnboxNullableTest should pass.
Actual behavior
Assert failure.
Regression?
No response
Known Workarounds
No response
Configuration
.NET 7.0.5
x64
Other information
ECMA-335 2012 p.431
The text was updated successfully, but these errors were encountered: