Skip to content

Commit a20930d

Browse files
committed
clean up suspensions when function ends
1 parent a917df1 commit a20930d

File tree

4 files changed

+33
-24
lines changed

4 files changed

+33
-24
lines changed

src/librustc_mir/interpret/eval_context.rs

+4-6
Original file line numberDiff line numberDiff line change
@@ -508,8 +508,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
508508
stmt: 0,
509509
});
510510

511-
let cur_frame = self.cur_frame();
512-
self.memory.set_cur_frame(cur_frame);
511+
self.memory.cur_frame = self.cur_frame();
513512

514513
if self.stack.len() > self.stack_limit {
515514
err!(StackFrameLimitReached)
@@ -520,14 +519,13 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
520519

521520
pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> {
522521
::log_settings::settings().indentation -= 1;
523-
self.memory.locks_lifetime_ended(None);
522+
self.end_region(None)?;
524523
let frame = self.stack.pop().expect(
525524
"tried to pop a stack frame, but there were none",
526525
);
527526
if !self.stack.is_empty() {
528-
// TODO: IS this the correct time to start considering these accesses as originating from the returned-to stack frame?
529-
let cur_frame = self.cur_frame();
530-
self.memory.set_cur_frame(cur_frame);
527+
// TODO: Is this the correct time to start considering these accesses as originating from the returned-to stack frame?
528+
self.memory.cur_frame = self.cur_frame();
531529
}
532530
match frame.return_to_block {
533531
StackPopCleanup::MarkStatic(mutable) => {

src/librustc_mir/interpret/memory.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ pub struct Memory<'a, 'tcx, M: Machine<'tcx>> {
268268
writes_are_aligned: Cell<bool>,
269269

270270
/// The current stack frame. Used to check accesses against locks.
271-
cur_frame: usize,
271+
pub cur_frame: usize,
272272
}
273273

274274
impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
@@ -530,10 +530,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
530530
}
531531
Ok(())
532532
}
533-
534-
pub(crate) fn set_cur_frame(&mut self, cur_frame: usize) {
535-
self.cur_frame = cur_frame;
536-
}
537533
}
538534

539535
/// Locking

src/librustc_mir/interpret/step.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
164164
}
165165
}
166166
EndRegion(ce) => {
167-
self.end_region(ce)?;
167+
self.end_region(Some(ce))?;
168168
}
169169

170170
// Defined to do nothing. These are added by optimization passes, to avoid changing the

src/librustc_mir/interpret/validation.rs

+27-12
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
4545
if self.tcx.sess.opts.debugging_opts.mir_emit_validate == 0 {
4646
return Ok(());
4747
}
48+
debug_assert!(self.memory.cur_frame == self.cur_frame());
4849

4950
// HACK: Determine if this method is whitelisted and hence we do not perform any validation.
5051
// We currently insta-UB on anything passing around uninitialized memory, so we have to whitelist
@@ -93,7 +94,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
9394
if query.mutbl == MutMutable {
9495
let lft = DynamicLifetime {
9596
frame: self.cur_frame(),
96-
region: Some(scope),
97+
region: Some(scope), // Notably, we only ever suspend things for given regions.
98+
// Suspending for the entire function does not make any sense.
9799
};
98100
trace!("Suspending {:?} until {:?}", query, scope);
99101
self.suspended.entry(lft).or_insert_with(Vec::new).push(
@@ -106,17 +108,30 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
106108
self.validate(query, mode)
107109
}
108110

109-
pub(crate) fn end_region(&mut self, scope: region::Scope) -> EvalResult<'tcx> {
110-
self.memory.locks_lifetime_ended(Some(scope));
111-
// Recover suspended lvals
112-
let lft = DynamicLifetime {
113-
frame: self.cur_frame(),
114-
region: Some(scope),
115-
};
116-
if let Some(queries) = self.suspended.remove(&lft) {
117-
for query in queries {
118-
trace!("Recovering {:?} from suspension", query);
119-
self.validate(query, ValidationMode::Recover(scope))?;
111+
/// Release locks and executes suspensions of the given region (or the entire fn, in case of None).
112+
pub(crate) fn end_region(&mut self, scope: Option<region::Scope>) -> EvalResult<'tcx> {
113+
debug_assert!(self.memory.cur_frame == self.cur_frame());
114+
self.memory.locks_lifetime_ended(scope);
115+
match scope {
116+
Some(scope) => {
117+
// Recover suspended lvals
118+
let lft = DynamicLifetime {
119+
frame: self.cur_frame(),
120+
region: Some(scope),
121+
};
122+
if let Some(queries) = self.suspended.remove(&lft) {
123+
for query in queries {
124+
trace!("Recovering {:?} from suspension", query);
125+
self.validate(query, ValidationMode::Recover(scope))?;
126+
}
127+
}
128+
}
129+
None => {
130+
// Clean suspension table of current frame
131+
let cur_frame = self.cur_frame();
132+
self.suspended.retain(|lft, _| {
133+
lft.frame != cur_frame // keep only what is in the other (lower) frames
134+
});
120135
}
121136
}
122137
Ok(())

0 commit comments

Comments
 (0)