-
Notifications
You must be signed in to change notification settings - Fork 12.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
Miri/CTFE discriminant computation happens at the wrong type #62138
Comments
@eddyb it would be nice to have some code that actually hits this incorrect overflow behavior, but I don't know enough about niches to massage the involved values into the right place. Could you help with that? |
cc #61696 |
@RalfJung You would start by using a small type, such as Let's say you'll use Come to think of it, wouldn't even Well, no, I'm wrong, there's this condition for "is this a niche (i.e. non-dataful) variant": rust/src/librustc_mir/interpret/operand.rs Line 647 in bdd4bda
Because all we're missing is a mask, we can only have more bits set, not less, which implies that the value can be larger than the correct one, not smaller. Given that the condition checks whether our value ( You can't literally use Really, you need to cause one of the non-dataful variants to have #[repr(u8)]
enum WithWraparoundInvalidValues {
X = 1,
Y = 254,
} The enum Foo {
A,
B,
C(WithWraparoundInvalidValues),
}
fn main() {
let x = Foo::B;
if let Foo::C(_) = x {
panic!();
}
} That trips an assertion failed: `(left == right)`
left: `0`,
right: `256`: Unsigned value 0x100 does not fit in 8 bits', src/librustc/mir/interpret/value.rs:290:9 |
Nice, thanks @eddyb <3 Now we got a test case for this issue. :) |
I tried to fix this by using machine arithmetic instead of host arithmetic, and found something odd: For types like (I am referring to the type and layout returned by |
Looks like |
@RalfJung Oh, right, we even have to special-case that for LLVM, if it's non-integer you can't have a range, but only one niche value (which will be Keep in mind that |
@eddyb what is a "castful" newtype? All I ask is that For |
The problem is that scalar newtypes of scalars usually have the same type of scalar, so no cast is required, AFAIK this would be the first one. Probably the closest thing right now is I guess right now we still do discriminant operations through memory (ugh), so it wouldn't hurt too much. But I suspect LLVM optimizations might suffer, as the same memory location would now be accessed as both a pointer and an integer, and I don't think LLVM will change it back to a pointer. Then again, maybe the final result is indistinguishable between integers and pointers? And we would need to treat the discriminant as an integer anyway if we wanted to support e.g. floats. I'll go try it and submit a PR if it's overall a cleanup and doesn't need special cases. |
Thanks! <3 |
Actually, the backtrace in @eddyb's testcase is from
There's also some arithmetic there, obviously. |
Yeah, I said "It's presumably related, but it does't even get to my |
Well I fixed the read-side first, so I won't be able to tell. ;) |
When loading discriminants of an enum that uses niche optimizations, Miri/CTFE has to do some arithmetic:
rust/src/librustc_mir/interpret/operand.rs
Lines 645 to 646 in bdd4bda
Currently, this happens on type
u128
. That's probably wrong, it should happen on the type of the discriminant. That will result in different overflow behavior.It's just addition and subtraction, so signed vs unsigned does not matter and we could just mask off the "too high" bits after each operation, as in:
rust/src/librustc_target/abi/mod.rs
Lines 664 to 669 in bdd4bda
However, it might be more elegant to use our
binary_*op
methods inoperator.rs
.Cc @oli-obk @eddyb
The text was updated successfully, but these errors were encountered: