don't expose all the borrow tracker stuff to the entire crate

This commit is contained in:
Ralf Jung 2023-11-13 20:39:17 +01:00
parent 28322532ac
commit 9840525ccf
2 changed files with 47 additions and 41 deletions

View File

@ -59,7 +59,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[derive(Debug)] #[derive(Debug)]
pub struct FrameState { pub struct FrameState {
/// The ID of the call this frame corresponds to. /// The ID of the call this frame corresponds to.
pub call_id: CallId, call_id: CallId,
/// If this frame is protecting any tags, they are listed here. We use this list to do /// If this frame is protecting any tags, they are listed here. We use this list to do
/// incremental updates of the global list of protected tags stored in the /// incremental updates of the global list of protected tags stored in the
@ -72,7 +72,7 @@ pub struct FrameState {
/// ///
/// This will contain one tag per reference passed to the function, so /// This will contain one tag per reference passed to the function, so
/// a size of 2 is enough for the vast majority of functions. /// a size of 2 is enough for the vast majority of functions.
pub protected_tags: SmallVec<[(AllocId, BorTag); 2]>, protected_tags: SmallVec<[(AllocId, BorTag); 2]>,
} }
impl VisitTags for FrameState { impl VisitTags for FrameState {
@ -85,29 +85,29 @@ fn visit_tags(&self, _visit: &mut dyn FnMut(BorTag)) {
#[derive(Debug)] #[derive(Debug)]
pub struct GlobalStateInner { pub struct GlobalStateInner {
/// Borrow tracker method currently in use. /// Borrow tracker method currently in use.
pub borrow_tracker_method: BorrowTrackerMethod, borrow_tracker_method: BorrowTrackerMethod,
/// Next unused pointer ID (tag). /// Next unused pointer ID (tag).
pub next_ptr_tag: BorTag, next_ptr_tag: BorTag,
/// Table storing the "base" tag for each allocation. /// Table storing the "base" tag for each allocation.
/// The base tag is the one used for the initial pointer. /// The base tag is the one used for the initial pointer.
/// We need this in a separate table to handle cyclic statics. /// We need this in a separate table to handle cyclic statics.
pub base_ptr_tags: FxHashMap<AllocId, BorTag>, base_ptr_tags: FxHashMap<AllocId, BorTag>,
/// Next unused call ID (for protectors). /// Next unused call ID (for protectors).
pub next_call_id: CallId, next_call_id: CallId,
/// All currently protected tags. /// All currently protected tags.
/// An item is protected if its tag is in this set, *and* it has the "protected" bit set. /// An item is protected if its tag is in this set, *and* it has the "protected" bit set.
/// We add tags to this when they are created with a protector in `reborrow`, and /// We add tags to this when they are created with a protector in `reborrow`, and
/// we remove tags from this when the call which is protecting them returns, in /// we remove tags from this when the call which is protecting them returns, in
/// `GlobalStateInner::end_call`. See `Stack::item_popped` for more details. /// `GlobalStateInner::end_call`. See `Stack::item_popped` for more details.
pub protected_tags: FxHashMap<BorTag, ProtectorKind>, protected_tags: FxHashMap<BorTag, ProtectorKind>,
/// The pointer ids to trace /// The pointer ids to trace
pub tracked_pointer_tags: FxHashSet<BorTag>, tracked_pointer_tags: FxHashSet<BorTag>,
/// The call ids to trace /// The call ids to trace
pub tracked_call_ids: FxHashSet<CallId>, tracked_call_ids: FxHashSet<CallId>,
/// Whether to recurse into datatypes when searching for pointers to retag. /// Whether to recurse into datatypes when searching for pointers to retag.
pub retag_fields: RetagFields, retag_fields: RetagFields,
/// Whether `core::ptr::Unique` gets special (`Box`-like) handling. /// Whether `core::ptr::Unique` gets special (`Box`-like) handling.
pub unique_is_unique: bool, unique_is_unique: bool,
} }
impl VisitTags for GlobalStateInner { impl VisitTags for GlobalStateInner {
@ -194,7 +194,7 @@ pub fn new(
} }
/// Generates a new pointer tag. Remember to also check track_pointer_tags and log its creation! /// Generates a new pointer tag. Remember to also check track_pointer_tags and log its creation!
pub fn new_ptr(&mut self) -> BorTag { fn new_ptr(&mut self) -> BorTag {
let id = self.next_ptr_tag; let id = self.next_ptr_tag;
self.next_ptr_tag = id.succ().unwrap(); self.next_ptr_tag = id.succ().unwrap();
id id
@ -210,7 +210,7 @@ pub fn new_frame(&mut self, machine: &MiriMachine<'_, '_>) -> FrameState {
FrameState { call_id, protected_tags: SmallVec::new() } FrameState { call_id, protected_tags: SmallVec::new() }
} }
pub fn end_call(&mut self, frame: &machine::FrameExtra<'_>) { fn end_call(&mut self, frame: &machine::FrameExtra<'_>) {
for (_, tag) in &frame for (_, tag) in &frame
.borrow_tracker .borrow_tracker
.as_ref() .as_ref()
@ -355,6 +355,38 @@ fn print_borrow_state(&mut self, alloc_id: AllocId, show_unnamed: bool) -> Inter
BorrowTrackerMethod::TreeBorrows => this.print_tree(alloc_id, show_unnamed), BorrowTrackerMethod::TreeBorrows => this.print_tree(alloc_id, show_unnamed),
} }
} }
fn on_stack_pop(
&self,
frame: &Frame<'mir, 'tcx, Provenance, FrameExtra<'tcx>>,
) -> InterpResult<'tcx> {
let this = self.eval_context_ref();
let borrow_tracker = this.machine.borrow_tracker.as_ref().unwrap();
// The body of this loop needs `borrow_tracker` immutably
// so we can't move this code inside the following `end_call`.
for (alloc_id, tag) in &frame
.extra
.borrow_tracker
.as_ref()
.expect("we should have borrow tracking data")
.protected_tags
{
// Just because the tag is protected doesn't guarantee that
// the allocation still exists (weak protectors allow deallocations)
// so we must check that the allocation exists.
// If it does exist, then we have the guarantee that the
// pointer is readable, and the implicit read access inserted
// will never cause UB on the pointer itself.
let (_, _, kind) = this.get_alloc_info(*alloc_id);
if matches!(kind, AllocKind::LiveData) {
let alloc_extra = this.get_alloc_extra(*alloc_id).unwrap();
let alloc_borrow_tracker = &alloc_extra.borrow_tracker.as_ref().unwrap();
alloc_borrow_tracker.release_protector(&this.machine, borrow_tracker, *tag)?;
}
}
borrow_tracker.borrow_mut().end_call(&frame.extra);
Ok(())
}
} }
/// Extra per-allocation data for borrow tracking /// Extra per-allocation data for borrow tracking

View File

@ -1409,34 +1409,8 @@ fn before_stack_pop(
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
// We want this *before* the return value copy, because the return place itself is protected // We want this *before* the return value copy, because the return place itself is protected
// until we do `end_call` here. // until we do `end_call` here.
if let Some(global_borrow_tracker) = &ecx.machine.borrow_tracker { if ecx.machine.borrow_tracker.is_some() {
// The body of this loop needs `global_borrow_tracker` immutably ecx.on_stack_pop(frame)?;
// so we can't move this code inside the following `end_call`.
for (alloc_id, tag) in &frame
.extra
.borrow_tracker
.as_ref()
.expect("we should have borrow tracking data")
.protected_tags
{
// Just because the tag is protected doesn't guarantee that
// the allocation still exists (weak protectors allow deallocations)
// so we must check that the allocation exists.
// If it does exist, then we have the guarantee that the
// pointer is readable, and the implicit read access inserted
// will never cause UB on the pointer itself.
let (_, _, kind) = ecx.get_alloc_info(*alloc_id);
if matches!(kind, AllocKind::LiveData) {
let alloc_extra = ecx.get_alloc_extra(*alloc_id).unwrap();
let alloc_borrow_tracker = &alloc_extra.borrow_tracker.as_ref().unwrap();
alloc_borrow_tracker.release_protector(
&ecx.machine,
global_borrow_tracker,
*tag,
)?;
}
}
global_borrow_tracker.borrow_mut().end_call(&frame.extra);
} }
Ok(()) Ok(())
} }