-
Notifications
You must be signed in to change notification settings - Fork 13.3k
generator fields are not necessarily initialized #56100
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -142,6 +142,7 @@ macro_rules! make_value_visitor { | |||||||||||||
self.walk_value(v) | ||||||||||||||
} | ||||||||||||||
/// Visit the given value as a union. No automatic recursion can happen here. | ||||||||||||||
/// Also called for the fields of a generator, which may or may not be initialized. | ||||||||||||||
#[inline(always)] | ||||||||||||||
fn visit_union(&mut self, _v: Self::V) -> EvalResult<'tcx> | ||||||||||||||
{ | ||||||||||||||
|
@@ -291,17 +292,28 @@ macro_rules! make_value_visitor { | |||||||||||||
// use that as an unambiguous signal for detecting primitives. Make sure | ||||||||||||||
// we did not miss any primitive. | ||||||||||||||
debug_assert!(fields > 0); | ||||||||||||||
self.visit_union(v)?; | ||||||||||||||
self.visit_union(v) | ||||||||||||||
}, | ||||||||||||||
layout::FieldPlacement::Arbitrary { ref offsets, .. } => { | ||||||||||||||
// FIXME: We collect in a vec because otherwise there are lifetime errors: | ||||||||||||||
// Projecting to a field needs (mutable!) access to `ecx`. | ||||||||||||||
let fields: Vec<EvalResult<'tcx, Self::V>> = | ||||||||||||||
(0..offsets.len()).map(|i| { | ||||||||||||||
v.project_field(self.ecx(), i as u64) | ||||||||||||||
}) | ||||||||||||||
.collect(); | ||||||||||||||
self.visit_aggregate(v, fields.into_iter())?; | ||||||||||||||
// Special handling needed for generators: All but the first field | ||||||||||||||
// (which is the state) are actually implicitly `MaybeUninit`, i.e., | ||||||||||||||
// they may or may not be initialized, so we cannot visit them. | ||||||||||||||
match v.layout().ty.sty { | ||||||||||||||
ty::Generator(..) => { | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Niche code also has an exception for generator fields rust/src/librustc/ty/layout.rs Lines 1812 to 1817 in 7a0cef7
Would it make sense to try to simplify all downstream code for generators by wrapping all its fields with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting, yes that would be the same exception. I am not sure how complicated it would be for generators to do this wrapping. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO generators should be treated like an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They don't have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I was considering that, but I don't know if that actually works in a non-scary way, as you'll want to switch from one variant to another without copying everything.
but why the entire generator? The discriminant field is perfectly safe to read and we could even do value range restrictions on it to be able to use niche optimizations on generators. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
In fact that would make perfect sense, it encodes the state after all and hence has a limited value range. |
||||||||||||||
let field = v.project_field(self.ecx(), 0)?; | ||||||||||||||
self.visit_aggregate(v, std::iter::once(Ok(field))) | ||||||||||||||
} | ||||||||||||||
_ => { | ||||||||||||||
// FIXME: We collect in a vec because otherwise there are lifetime | ||||||||||||||
// errors: Projecting to a field needs access to `ecx`. | ||||||||||||||
let fields: Vec<EvalResult<'tcx, Self::V>> = | ||||||||||||||
(0..offsets.len()).map(|i| { | ||||||||||||||
v.project_field(self.ecx(), i as u64) | ||||||||||||||
}) | ||||||||||||||
.collect(); | ||||||||||||||
self.visit_aggregate(v, fields.into_iter()) | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
}, | ||||||||||||||
layout::FieldPlacement::Array { .. } => { | ||||||||||||||
// Let's get an mplace first. | ||||||||||||||
|
@@ -317,10 +329,9 @@ macro_rules! make_value_visitor { | |||||||||||||
.map(|f| f.and_then(|f| { | ||||||||||||||
Ok(Value::from_mem_place(f)) | ||||||||||||||
})); | ||||||||||||||
self.visit_aggregate(v, iter)?; | ||||||||||||||
self.visit_aggregate(v, iter) | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
Ok(()) | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
} | ||||||||||||||
|
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.
I don't see this happening in the code below.
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 yeah I went back on this because it doesn't work very well... I guess I could still do it an go through
visit_field
though.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.
Actually no that doesn't work, it doesn't have a union type. I don't think there is a way to visit the other generator fields at all with the current interface, and it doesn't seem worth extending the interface?
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 yea, that's totally fine, as long as the comments mirror reality ;)
Well, as long as validation doesn't get hickups elsewhere because https://github.com/solson/miri/blob/adfede5cec2c8a136830f7fc309dbb45ac7a098a/src/helpers.rs#L221 wasn't visited in miri.
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.
Hm, that is a good point. I forgot that I was using
visit_union
there.This is relevant when determining where there are
UnsafeCell
inside a generator. If there is noUnsafeCell
, shared references enforce memory to be frozen. So we probably should go conservatively type-based here like we do for unions... dang.Just calling
visit_union
after doing the field projections would actually work, but it would violate the protocol that lets a visitor keep track of which "path" inside the data structure we are at. The only visitor relying on the path is validation, which doesn't do anything for unions, so this is fine in principle... but it's not nice. Any ideas?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.
I added a new
visit_generator_field
hook for this. Now at least it makes sense, and likely nobody will ever overwrite that hook...