Skip to content

Commit 8c7ac81

Browse files
expand roots comment & refactor check_strong_protector
1 parent 2b069d9 commit 8c7ac81

File tree

1 file changed

+50
-52
lines changed
  • src/borrow_tracker/tree_borrows

1 file changed

+50
-52
lines changed

src/borrow_tracker/tree_borrows/tree.rs

Lines changed: 50 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,12 @@ pub struct Tree {
302302
///
303303
/// Sorted according to `BorTag` from low to high. This also means the main root is `root[0]`.
304304
///
305+
/// The actual structure should be a single tree but with wildcard provenance we approximate
306+
/// this with this ordered set of trees. Each wildcard subtree could be the direct child of
307+
/// any exposed tag (that is smaller than the root). This also means that it can only be the
308+
/// child of a tree that comes before it in the vec ensuring we don't have any cycles in our
309+
/// approximated tree.
310+
///
305311
/// Has array size 2 because that still ensures the minimum size for SmallVec.
306312
pub(super) roots: SmallVec<[UniIndex; 2]>,
307313
}
@@ -808,74 +814,66 @@ impl<'tcx> Tree {
808814
span,
809815
)?;
810816

817+
let start_idx = match prov {
818+
ProvenanceExtra::Concrete(tag) => Some(self.tag_mapping.get(&tag).unwrap()),
819+
ProvenanceExtra::Wildcard => None,
820+
};
821+
811822
// Check if this breaks any strong protector.
812823
// (Weak protectors are already handled by `perform_access`.)
813824
for (loc_range, loc) in self.locations.iter_mut(access_range.start, access_range.size) {
814-
let start_idx = match prov {
815-
ProvenanceExtra::Concrete(tag) => Some(self.tag_mapping.get(&tag).unwrap()),
816-
ProvenanceExtra::Wildcard => None,
817-
};
818-
// Returns an error if `idx` has a strong protector.
819-
let check_strong_protector = |args: NodeAppArgs<'_>| {
820-
let node = args.nodes.get(args.idx).unwrap();
821-
822-
let perm = args
823-
.loc
824-
.perms
825-
.get(args.idx)
826-
.copied()
827-
.unwrap_or_else(|| node.default_location_state());
828-
if global.borrow().protected_tags.get(&node.tag)
825+
// Checks the tree containing `idx` for strong protector violations.
826+
// It does this in traversal order.
827+
let mut check_tree = |idx| {
828+
TreeVisitor { nodes: &mut self.nodes, loc }.traverse_this_parents_children_other(
829+
idx,
830+
// Visit all children, skipping none.
831+
|_| ContinueTraversal::Recurse,
832+
|args: NodeAppArgs<'_>| {
833+
let node = args.nodes.get(args.idx).unwrap();
834+
835+
let perm = args
836+
.loc
837+
.perms
838+
.get(args.idx)
839+
.copied()
840+
.unwrap_or_else(|| node.default_location_state());
841+
if global.borrow().protected_tags.get(&node.tag)
829842
== Some(&ProtectorKind::StrongProtector)
830843
// Don't check for protector if it is a Cell (see `unsafe_cell_deallocate` in `interior_mutability.rs`).
831844
// Related to https://github.com/rust-lang/rust/issues/55005.
832845
&& !perm.permission.is_cell()
833846
// Only trigger UB if the accessed bit is set, i.e. if the protector is actually protecting this offset. See #4579.
834847
&& perm.accessed
835-
{
836-
Err(TbError {
837-
conflicting_info: &node.debug_info,
838-
access_cause: diagnostics::AccessCause::Dealloc,
839-
alloc_id,
840-
error_offset: loc_range.start,
841-
error_kind: TransitionError::ProtectedDealloc,
842-
accessed_info: start_idx
843-
.map(|idx| &args.nodes.get(idx).unwrap().debug_info),
844-
}
845-
.build())
846-
} else {
847-
Ok(())
848-
}
848+
{
849+
Err(TbError {
850+
conflicting_info: &node.debug_info,
851+
access_cause: diagnostics::AccessCause::Dealloc,
852+
alloc_id,
853+
error_offset: loc_range.start,
854+
error_kind: TransitionError::ProtectedDealloc,
855+
accessed_info: start_idx
856+
.map(|idx| &args.nodes.get(idx).unwrap().debug_info),
857+
}
858+
.build())
859+
} else {
860+
Ok(())
861+
}
862+
},
863+
)
849864
};
850865
// If we have a start index we first check its subtree in traversal order.
851866
// This results in us showing the error of the closest node instead of an
852867
// arbitrary one.
853-
let accessed_root = if let Some(start_idx) = start_idx {
854-
Some(
855-
TreeVisitor { nodes: &mut self.nodes, loc }
856-
.traverse_this_parents_children_other(
857-
start_idx,
858-
// Visit all children, skipping none.
859-
|_| ContinueTraversal::Recurse,
860-
check_strong_protector,
861-
)?,
862-
)
863-
} else {
864-
None
865-
};
866-
// Afterwards we check all tags in arbitrary order, so that we also catch
867-
// protectors on different subtrees.
868-
// (This unnecessarily checks the tags of `start_idx`s subtree again)
869-
for root in self.roots.iter() {
868+
let accessed_root = start_idx.map(&mut check_tree).transpose()?;
869+
// Afterwards we check all other trees.
870+
// We iterate over the list in reverse order to ensure that we do not visit
871+
// a parent before its child.
872+
for root in self.roots.iter().rev() {
870873
if Some(*root) == accessed_root {
871874
continue;
872875
}
873-
TreeVisitor { nodes: &mut self.nodes, loc }.traverse_this_parents_children_other(
874-
*root,
875-
// Visit all children, skipping none.
876-
|_| ContinueTraversal::Recurse,
877-
check_strong_protector,
878-
)?;
876+
check_tree(*root)?;
879877
}
880878
}
881879
interp_ok(())

0 commit comments

Comments
 (0)