-
Notifications
You must be signed in to change notification settings - Fork 4.5k
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 optimizations can produce incorrect IL when dealing with byrefs #12438
Comments
The jit is likely not sufficiently careful about re-association in address formation. In normal usage, address computations are always adding positive values, and so it doesn't matter what order the adds are performed. Fixing this in general without causing regression may not be easy -- for example, we may need to surface implicit assumptions about the non-negativity of some variable addends below guard checks. I suspect this is a long-standing issue with jitted codegen in general. Will put in 3.0 for now but will likely move this to future once we've looked at it more deeply. |
Likely culprit is |
I'll investigate. |
The culprit is this code in I have a change that allows this transformation for byrefs only if the constant is not negative and the other operand is unsigned. With that I get this code for the issue example:
|
I'll check the diffs to see if this causes many regressions. |
Morph has a transformation ((x + const) + y) => ((x + y) + const). If x or y is a GC pointer and one of the int operands may be negative, this may result in a byref temp that points outside of the ref object. If the code is in a non-interruptible region and a GC happens, the byref won't be updated. This change restricts the transformation so that if one of the non-const operands is a GC pointer, then it's allowed only if the constant operand is not negative and the other int operand is unsigned and, therefore, is also not negative. Fixes #23792.
Morph has a transformation ((x + const) + y) => ((x + y) + const). If x or y is a GC pointer and one of the int operands may be negative, this may result in a byref temp that points outside of the ref object. If the code is in a non-interruptible region and a GC happens, the byref won't be updated. This change restricts the transformation so that if one of the non-const operands is a GC pointer, then it's allowed only if the constant operand is not negative and the other int operand is unsigned and, therefore, is also not negative. Fixes #23792.
Morph has transformations ((x + const) + y) => ((x + y) + const) and ((x + const1) + (y + const2)) => ((x + y) + (const1 + const2)) If x or y is a GC pointer and one of the int operands may be negative, this may result in a byref temp that points outside of the ref object. If the code is in a non-interruptible region and a GC happens, the byref won't be updated. This change disallows the transformations if one of the non-const operands is a GC pointer. Fixes #23792.
Morph has transformations ((x + const) + y) => ((x + y) + const) and ((x + const1) + (y + const2)) => ((x + y) + (const1 + const2)) If x or y is a GC pointer and one of the int operands may be negative, this may result in a byref temp that points outside of the ref object. If the code is in a non-interruptible region and a GC happens, the byref won't be updated. This change disallows the transformations if one of the non-const operands is a GC pointer. Fixes #23792.
Morph has transformations ((x + const) + y) => ((x + y) + const) and ((x + const1) + (y + const2)) => ((x + y) + (const1 + const2)) If x or y is a GC pointer and one of the int operands may be negative, this may result in a byref temp that points outside of the ref object. If the code is in a non-interruptible region and a GC happens, the byref won't be updated. This change disallows the transformations if one of the non-const operands is a GC pointer. Fixes #23792.
(See also dotnet/coreclr#23783 (comment).)
Repro:
Codegen:
Here,
rcx := theRef&
,rdx := a
, andr8 := b
. The JIT has incorrectly rearranged the addition of a and the subtraction of 8. It's possible that the caller required the operations to be done specifically in that order to avoid a GC hole. The intermediate valueref byte temp = ref theRef + a
could result in a temp that points beyond the bounds of the GC-tracked object.Edit: the following codegen would have been acceptable, since it doesn't result in an intermediate byref.
The text was updated successfully, but these errors were encountered: