Skip to content
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

generator fields are not necessarily initialized #56100

Merged
merged 3 commits into from
Nov 25, 2018
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 21 additions & 11 deletions src/librustc_mir/interpret/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,17 +291,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(..) => {
Copy link
Contributor

Choose a reason for hiding this comment

The 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

// Locals variables which live across yields are stored
// in the generator type as fields. These may be uninitialized
// so we don't look for niches there.
if let ty::Generator(..) = layout.ty.sty {
return Ok(None);
}

Would it make sense to try to simplify all downstream code for generators by wrapping all its fields with MaybeUninit very early?

Copy link
Member Author

Choose a reason for hiding this comment

The 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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO generators should be treated like an union with field offsets.
Unless we want to generate "variants" for the states involved, which would be a bit more work, but would provide a safe view into the state of the generator.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They don't have Union layout though, so right now they need special treatment everywhere.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless we want to generate "variants" for the states involved, which would be a bit more work, but would provide a safe view into the state of the generator.

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.

IMO generators should be treated like an union with field offsets.

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

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.
Expand All @@ -317,10 +328,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(())
}
}
}
Expand Down