You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
enum padding incorrectly has Scalar::Initialized layout #96158
#94527 extended our Scalar layout with the notion of whether a scalar has to be initialized or not. Miri enforces this, and also uses it to know whether it can use a more efficient representation for scalars that have to be initialized.
However, in some situations we currently compute a Scalar::Initialized layout when it should be Scalar::Union (aka "may be uninitialized" -- maybe we should rename it to Scalar::MaybeUninit). Specifically, Option<u32>has:
Note that this claims that the second field must be always initialized. This is not true though, since for a None that second field is padding and hence does not have to be initialized.
(To be clear, this bug only causes problems in Miri, not during regular codegen -- at least for now, since we don't [yet] tell LLVM about this "must be initialized" thing.)
use std::mem::MaybeUninit;fnmain(){unsafe{letmut x = [MaybeUninit::<i32>::zeroed();3];// Put in a ptr into the last 8 bytes.
x.as_mut_ptr().offset(1).cast::<&i32>().write_unaligned(&0);// Read first 8 bytes as an `Option<i32>`let c = x.as_ptr().cast::<Option<i32>>().read();println!("{:?}", c);}}
This can probably be turned into a CTFE testcase as well.
Ah, that testcase will actually still fail since it is still copying parts of a pointer.
A testcase that demonstrates the bug would either require us to validate ScalarPair, or it'd have to be something horrible where parts of that padding are uninit, and we'd test if the init'ed parts are preserved. (Which is not actually guaranteed, padding can reset to uninit on a typed copy like this.)
Variants seem to be even wilder (according to my debugging while working on #96185): the variant of a ScalarPair enum might have Aggregate layout! That's a disaster since Miri assumes that all ScalarPair values have ScalarPair layout. That seemed like a reasonable sanity check, but apparently it is not true...
Except codegen also assumes this, but somehow there it works out. Maybe it handles downcasts differently.
Activity
RalfJung commentedon Apr 17, 2022
Here's a stand-alone reproducer for Miri:
This can probably be turned into a CTFE testcase as well.
RalfJung commentedon Apr 17, 2022
FWIW one reason this went unnoticed is that we don't actually check
ScalarPairstuff during validation:rust/compiler/rustc_const_eval/src/interpret/validity.rs
Lines 822 to 827 in 38004b7
Maybe we should have a sort of debug mode where we do that check anyway? (For normal Miri operation this sounds like a waste though.)
RalfJung commentedon Apr 18, 2022
Ah, that testcase will actually still fail since it is still copying parts of a pointer.
A testcase that demonstrates the bug would either require us to validate ScalarPair, or it'd have to be something horrible where parts of that padding are uninit, and we'd test if the init'ed parts are preserved. (Which is not actually guaranteed, padding can reset to uninit on a typed copy like this.)
oli-obk commentedon Apr 18, 2022
Oh fun. So this is specifically about the enum layout and not the layout of a downcasted variant, right?
RalfJung commentedon Apr 18, 2022
Yes. I have not looked at the layout of the downcasted variants.
RalfJung commentedon Apr 18, 2022
Variants seem to be even wilder (according to my debugging while working on #96185): the variant of a
ScalarPairenum might haveAggregatelayout! That's a disaster since Miri assumes that allScalarPairvalues haveScalarPairlayout. That seemed like a reasonable sanity check, but apparently it is not true...Except codegen also assumes this, but somehow there it works out. Maybe it handles downcasts differently.
Rollup merge of rust-lang#96714 - RalfJung:scalar-pair-debug, r=oli-obk