提交 15919774 编写于 作者: R Ralf Jung

clean up suspensions when function ends

上级 bc2f9259
......@@ -508,8 +508,7 @@ fn collect_storage_annotations<'tcx>(mir: &'tcx mir::Mir<'tcx>) -> HashSet<mir::
stmt: 0,
});
let cur_frame = self.cur_frame();
self.memory.set_cur_frame(cur_frame);
self.memory.cur_frame = self.cur_frame();
if self.stack.len() > self.stack_limit {
err!(StackFrameLimitReached)
......@@ -520,14 +519,13 @@ fn collect_storage_annotations<'tcx>(mir: &'tcx mir::Mir<'tcx>) -> HashSet<mir::
pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> {
::log_settings::settings().indentation -= 1;
self.memory.locks_lifetime_ended(None);
self.end_region(None)?;
let frame = self.stack.pop().expect(
"tried to pop a stack frame, but there were none",
);
if !self.stack.is_empty() {
// TODO: IS this the correct time to start considering these accesses as originating from the returned-to stack frame?
let cur_frame = self.cur_frame();
self.memory.set_cur_frame(cur_frame);
// TODO: Is this the correct time to start considering these accesses as originating from the returned-to stack frame?
self.memory.cur_frame = self.cur_frame();
}
match frame.return_to_block {
StackPopCleanup::MarkStatic(mutable) => {
......
......@@ -268,7 +268,7 @@ pub struct Memory<'a, 'tcx, M: Machine<'tcx>> {
writes_are_aligned: Cell<bool>,
/// The current stack frame. Used to check accesses against locks.
cur_frame: usize,
pub cur_frame: usize,
}
impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
......@@ -530,10 +530,6 @@ pub fn check_bounds(&self, ptr: MemoryPointer, access: bool) -> EvalResult<'tcx>
}
Ok(())
}
pub(crate) fn set_cur_frame(&mut self, cur_frame: usize) {
self.cur_frame = cur_frame;
}
}
/// Locking
......
......@@ -164,7 +164,7 @@ fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<'tcx> {
}
}
EndRegion(ce) => {
self.end_region(ce)?;
self.end_region(Some(ce))?;
}
// Defined to do nothing. These are added by optimization passes, to avoid changing the
......
......@@ -45,6 +45,7 @@ pub(crate) fn validation_op(
if self.tcx.sess.opts.debugging_opts.mir_emit_validate == 0 {
return Ok(());
}
debug_assert!(self.memory.cur_frame == self.cur_frame());
// HACK: Determine if this method is whitelisted and hence we do not perform any validation.
// We currently insta-UB on anything passing around uninitialized memory, so we have to whitelist
......@@ -93,7 +94,8 @@ pub(crate) fn validation_op(
if query.mutbl == MutMutable {
let lft = DynamicLifetime {
frame: self.cur_frame(),
region: Some(scope),
region: Some(scope), // Notably, we only ever suspend things for given regions.
// Suspending for the entire function does not make any sense.
};
trace!("Suspending {:?} until {:?}", query, scope);
self.suspended.entry(lft).or_insert_with(Vec::new).push(
......@@ -106,8 +108,12 @@ pub(crate) fn validation_op(
self.validate(query, mode)
}
pub(crate) fn end_region(&mut self, scope: region::Scope) -> EvalResult<'tcx> {
self.memory.locks_lifetime_ended(Some(scope));
/// Release locks and executes suspensions of the given region (or the entire fn, in case of None).
pub(crate) fn end_region(&mut self, scope: Option<region::Scope>) -> EvalResult<'tcx> {
debug_assert!(self.memory.cur_frame == self.cur_frame());
self.memory.locks_lifetime_ended(scope);
match scope {
Some(scope) => {
// Recover suspended lvals
let lft = DynamicLifetime {
frame: self.cur_frame(),
......@@ -119,6 +125,15 @@ pub(crate) fn end_region(&mut self, scope: region::Scope) -> EvalResult<'tcx> {
self.validate(query, ValidationMode::Recover(scope))?;
}
}
}
None => {
// Clean suspension table of current frame
let cur_frame = self.cur_frame();
self.suspended.retain(|lft, _| {
lft.frame != cur_frame // keep only what is in the other (lower) frames
});
}
}
Ok(())
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册