From e7faf046c0aca0438d948461b8a39046281248ea Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Mon, 17 Oct 2022 22:17:07 -0400 Subject: [PATCH] Never start the Stack::retain loop at offset 0 so that the left element is always inbounds --- src/tools/miri/src/stacked_borrows/stack.rs | 12 +++++++---- .../pass/stacked-borrows/unknown-bottom-gc.rs | 21 +++++++++++++++++++ 2 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs diff --git a/src/tools/miri/src/stacked_borrows/stack.rs b/src/tools/miri/src/stacked_borrows/stack.rs index 07c211512f8..aa549e34c5f 100644 --- a/src/tools/miri/src/stacked_borrows/stack.rs +++ b/src/tools/miri/src/stacked_borrows/stack.rs @@ -43,10 +43,14 @@ impl Stack { pub fn retain(&mut self, tags: &FxHashSet) { let mut first_removed = None; - // For stacks with a known bottom, we never consider removing the bottom-most tag, because - // that is the base tag which exists whether or not there are any pointers to the - // allocation. - let mut read_idx = if self.unknown_bottom.is_some() { 0 } else { 1 }; + // We never consider removing the bottom-most tag. For stacks without an unknown + // bottom this preserves the base tag. + // Note that the algorithm below is based on considering the tag at read_idx - 1, + // so precisely considering the tag at index 0 for removal when we have an unknown + // bottom would complicate the implementation. The simplification of not considering + // it does not have a significant impact on the degree to which the GC mititages + // memory growth. + let mut read_idx = 1; let mut write_idx = read_idx; while read_idx < self.borrows.len() { let left = self.borrows[read_idx - 1]; diff --git a/src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs b/src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs new file mode 100644 index 00000000000..e62ee528686 --- /dev/null +++ b/src/tools/miri/tests/pass/stacked-borrows/unknown-bottom-gc.rs @@ -0,0 +1,21 @@ +//@compile-flags: -Zmiri-permissive-provenance +#![feature(strict_provenance)] + +use std::ptr; + +fn main() { + let mut v = 1u8; + let ptr = &mut v as *mut u8; + + // Expose the allocation and use the exposed pointer, creating an unknown bottom + unsafe { + let p: *mut u8 = ptr::from_exposed_addr::(ptr.expose_addr()) as *mut u8; + *p = 1; + } + + // Pile on a lot of SharedReadOnly at the top of the stack + let r = &v; + for _ in 0..1024 { + let _x = &*r; + } +}