-
Notifications
You must be signed in to change notification settings - Fork 13k
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
[const-prop] Fix ICE due to underflow when calculating enum discriminant #66857
Conversation
.checked_sub(variants_start) | ||
.expect("overflow computing relative variant idx"); | ||
|
||
let (variant_index_relative, op) = if variant_index.as_u32() >= variants_start { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use overflowing_sub here to remove some duplication. The add/sub decision can be made on the overflow bool returned by overflowing_sub
cc @RalfJung |
Cc @eddyb does that look right to you? I thought enum discriminant always use subtraction here. |
// We need to use machine arithmetic when taking into account `niche_start`: | ||
// discr_val = variant_index_relative + niche_start_val | ||
let discr_layout = self.layout_of(discr_layout.value.to_int_ty(*self.tcx))?; | ||
let niche_start_val = ImmTy::from_uint(niche_start, discr_layout); | ||
let variant_index_relative_val = | ||
ImmTy::from_uint(variant_index_relative, discr_layout); | ||
let discr_val = self.binary_op( | ||
mir::BinOp::Add, | ||
op, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem right to me... in the 2nd branch above, what happens (compared to earlier) is that variant_index_relative
is negative, but here by changing the operator you are negating the second operand, niche_start_val
. So the entire result is the negation of what it used to be. Don't you also have to swap the operands?
Either way, this needs a detailed comment why both branches above are correct. Also we should understand why LLVM codegen doesn't need a branch like this.
// compile-flags: --crate-type lib | ||
|
||
// Regression test for ICE which occurred when const propagating an enum whose discriminant | ||
// niche triggered an integer underflow conmupting a delta. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a way to also trigger this ICE in standalone Miri? I'd prefer to have such important parts of the Miri engine not just covered indirectly through an optimization.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given #66857 (comment) I'm not sure that's possible, since this is necessarily an initialization of an uninhabited variant, and that's dead code.
Miri likely wouldn't have had this bug for so long if it was actually executing the code that is being constant-folded here.
I'm sorry, what is going on? How can any niche variant be before the first niche variant? Are you sure miri isn't missing a check for uninhabited variants? rust/src/librustc_codegen_ssa/mir/place.rs Lines 335 to 337 in fe969f4
EDIT2: okay I was very shocked at first but I guess this would generally be dead code and only the const-prop optimization would attempt to execute it, so that's why miri didn't need to handle uninhabited variants like codegen does. |
@@ -1082,17 +1082,21 @@ where | |||
} | |||
if variant_index != dataful_variant { | |||
let variants_start = niche_variants.start().as_u32(); | |||
let variant_index_relative = variant_index.as_u32() | |||
.checked_sub(variants_start) | |||
.expect("overflow computing relative variant idx"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In codegen this isn't even checked, it's a plain -
, because this is impossible for indices.
@@ -1082,17 +1082,21 @@ where | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, btw, this check seems pointless, it's impossible for variant_index
to be out of range (without rustc being broken), so you could just ICE here if you wanted to (but there's not really any point, dest.layout.for_variant(variant_index)
would panic trying to index with it, anyway).
@RalfJung It occurs to me that miri might not want to handle |
Could you explain in a bit more detail what this problem here has to do with uninhabited variants?
So the semantics of |
The bug here is that miri sees a
Uhhh I was a bit unclear. I meant writing undef bytes specifically for uninhabited variants. For the record, cc @matthewjasper @spastorino perhaps borrowck could use such a rule for |
Since only const prop cares about this, maybe we can insert a machine hook that allows const prop to overwrite the destination with undef. We only need this if the destination has gotten anything else written before the |
I was under the assumption this wouldn't be considered an UB error, hence suggesting doing something other than a noop (which is what codegen does). But maybe it makes sense as an error, just not an UB |
We can emit the Unreachable UB error: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/mir/interpret/enum.UndefinedBehaviorInfo.html#variant.Unreachable const prop already ignores it |
I think @eddyb hit the nail on the head here. If I add a similar check as the one in codegen, that resolves the issue as well. Does anyone object to doing that patch instead? Edit: @eddyb you mentioned to me that you'd prefer if this used something named more meaningful than |
Closing in favor of #66960 |
I explained on the new PR, but I think |
…obk,RalfJung [const-prop] Fix ICE calculating enum discriminant Fixes rust-lang#66787 Different approach than rust-lang#66857 r? @oli-obk cc @RalfJung @eddyb
…obk,RalfJung [const-prop] Fix ICE calculating enum discriminant Fixes rust-lang#66787 Different approach than rust-lang#66857 r? @oli-obk cc @RalfJung @eddyb
Fixes #66787
r? @oli-obk
cc @RalfJung