Description
When we optimized product types with uninhabited fields to be ZST, partial initialization was overlooked, i.e. writes to the inhabited sibling fields are allowed despite missing in the layout.
Thankfully, it's impossible to read or borrow such fields, because the whole value must be initialized (although this may be relaxed in the future). However , the initialized fields are still dropped.
One way we could work around this is track uninhabitedness but only take advantage of it in enums.
(I am not aware of a solution that works with variant types, which I think we should keep in mind.)
EDIT: we can disallow creating the enum
from an incomplete variant. This is also required by niche optimizations because the niche slot being uninitialized would result in UB.
EDIT2: incomplete variants might be possible today already (#49298 (comment)).
As an example, in debug mode, this snippet prints 0
, because x.1
and y
overlap:
enum Void {}
fn main() {
let mut x: (Void, usize);
let y = 1;
x.1 = 0;
println!("{}", y)
}
Activity
LunaBorowska commentedon Mar 23, 2018
Seems I-unsound.
LunaBorowska commentedon Mar 23, 2018
Also, this regression was introduced in Rust 1.24.0 from what I see, this correctly works in 1.23.0.
ExpHP commentedon Mar 24, 2018
To pile on the scary labels, that also makes this a regression from stable to stable!
eddyb commentedon Mar 28, 2018
#48493 looks like an instance of this - cc @alexcrichton
hanna-kruppe commentedon Mar 28, 2018
@eddyb
Weak
creates a value of the uninhabited type viamem::uninitialized
, it does not perform partial initalization. It's UB anyway. This issue (edit: resolving this issue) would at best make the code working-but-still-UB.bstrie commentedon Mar 28, 2018
@rkruppe is there a separate bug for that?
hanna-kruppe commentedon Mar 28, 2018
@eddyb Uh, I guess #48493 is that bug? Although if we land a workaround before the proper fix (
MaybeUninitialized
with unsizing support) becomes available, we should make sure we open a new bug for tracking removal of the workaround and introduction of the proper fix.eddyb commentedon Apr 11, 2018
There's potentially an even more problematic implication here: initializing an uninhabited (because of its fields) variant and panicking while doing so could also result in writing over data following the whole
enum
, assuming the data is larger than theenum
itself, e.g.:This might be hard to demonstrate today, because of some extra temporaries, but optimizations would likely prefer to write to
x
directly, which would spell disaster.I'm not sure what a proper solution would be here, we certainly need to discuss it.
nikomatsakis commentedon Apr 12, 2018
We discussed in the meeting. It seems like the rules want to be:
!
is treated like any ZST)This ensures there is space for non-ZST data... we need to do this if we want to be able to optimize temporaries away pre-monomorphization.
31 remaining items