Skip to content

Commit db93abe

Browse files
committed
Fix bugs where unique_range became invalid
And also expand the cache integrity checks to cover this case, and generally assert a lot more about the unique_range, then tighten up sloppy implementation scenarios that this uncovered.
1 parent a7e51ac commit db93abe

File tree

1 file changed

+32
-10
lines changed

1 file changed

+32
-10
lines changed

src/stacked_borrows/stack.rs

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ impl<'tcx> Stack {
9292
}
9393
}
9494

95+
// Check that all Unique items fall within unique_range.
9596
for (idx, item) in self.borrows.iter().enumerate() {
9697
if item.perm() == Permission::Unique {
9798
assert!(
@@ -102,6 +103,18 @@ impl<'tcx> Stack {
102103
);
103104
}
104105
}
106+
107+
// Check that the unique_range is a valid index into the borrow stack.
108+
let uniques = &self.borrows[self.unique_range.clone()];
109+
110+
// Check that the start of the unique_range is precise.
111+
if let Some(first_unique) = uniques.first() {
112+
assert_eq!(first_unique.perm(), Permission::Unique);
113+
}
114+
// We cannot assert that the unique range is exact on the upper end.
115+
// When we pop items within the unique range, setting the end of the range precisely
116+
// require doing a linear search of the borrow stack, which is exactly the kind of
117+
// operation that all this caching exists to avoid.
105118
}
106119

107120
/// Find the item granting the given kind of access to the given tag, and return where
@@ -227,9 +240,14 @@ impl<'tcx> Stack {
227240
self.unique_range.end += 1;
228241
}
229242
if new.perm() == Permission::Unique {
230-
// Make sure the possibly-unique range contains the new borrow
231-
self.unique_range.start = self.unique_range.start.min(new_idx);
232-
self.unique_range.end = self.unique_range.end.max(new_idx + 1);
243+
// If this is the first Unique, set the range to contain just the new item.
244+
if self.unique_range == (0..0) {
245+
self.unique_range = new_idx..new_idx + 1;
246+
} else {
247+
// We already have other Unique items, expand the range to include the new item
248+
self.unique_range.start = self.unique_range.start.min(new_idx);
249+
self.unique_range.end = self.unique_range.end.max(new_idx + 1);
250+
}
233251
}
234252

235253
// The above insert changes the meaning of every index in the cache >= new_idx, so now
@@ -282,6 +300,10 @@ impl<'tcx> Stack {
282300
// cache when it has been cleared and not yet refilled.
283301
self.borrows.clear();
284302
self.unknown_bottom = Some(tag);
303+
#[cfg(feature = "stack-cache")]
304+
{
305+
self.unique_range = 0..0;
306+
}
285307
}
286308

287309
/// Find all `Unique` elements in this borrow stack above `granting_idx`, pass a copy of them
@@ -298,7 +320,7 @@ impl<'tcx> Stack {
298320

299321
if disable_start <= unique_range.end {
300322
let lower = unique_range.start.max(disable_start);
301-
let upper = (unique_range.end + 1).min(self.borrows.len());
323+
let upper = self.unique_range.end;
302324
for item in &mut self.borrows[lower..upper] {
303325
if item.perm() == Permission::Unique {
304326
log::trace!("access: disabling item {:?}", item);
@@ -315,14 +337,14 @@ impl<'tcx> Stack {
315337
}
316338

317339
#[cfg(feature = "stack-cache")]
318-
if disable_start < self.unique_range.start {
340+
if disable_start <= self.unique_range.start {
319341
// We disabled all Unique items
320342
self.unique_range.start = 0;
321343
self.unique_range.end = 0;
322344
} else {
323-
// Truncate the range to disable_start. This is + 2 because we are only removing
324-
// elements after disable_start, and this range does not include the end.
325-
self.unique_range.end = self.unique_range.end.min(disable_start + 1);
345+
// Truncate the range to only include items up to the index that we started disabling
346+
// at.
347+
self.unique_range.end = self.unique_range.end.min(disable_start);
326348
}
327349

328350
#[cfg(debug_assertions)]
@@ -369,12 +391,12 @@ impl<'tcx> Stack {
369391
self.cache.items[i] = base_tag;
370392
}
371393

372-
if start < self.unique_range.start.saturating_sub(1) {
394+
if start <= self.unique_range.start {
373395
// We removed all the Unique items
374396
self.unique_range = 0..0;
375397
} else {
376398
// Ensure the range doesn't extend past the new top of the stack
377-
self.unique_range.end = self.unique_range.end.min(start + 1);
399+
self.unique_range.end = self.unique_range.end.min(start);
378400
}
379401
} else {
380402
self.unique_range = 0..0;

0 commit comments

Comments
 (0)