@@ -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