@@ -111,7 +111,7 @@ impl LocationState {
111111 // We need to update the wildcard state, if the permission
112112 // of an exposed pointer changes.
113113 if node. is_exposed {
114- let access_type = self . permission . strongest_allowed_child_access ( protected) ;
114+ let access_type = self . permission . strongest_allowed_local_access ( protected) ;
115115 WildcardState :: update_exposure ( idx, access_type, nodes, wildcard_accesses) ;
116116 }
117117 }
@@ -1034,6 +1034,9 @@ impl<'tcx> LocationTree {
10341034 wildcard_state. access_relatedness ( access_kind, only_foreign)
10351035 } ;
10361036
1037+ // Whether there is an exposed node in this tree that allows this access.
1038+ let mut has_valid_exposed = false ;
1039+
10371040 // This does a traversal across the tree updating children before their parents. The
10381041 // difference to `perform_normal_access` is that we take the access relatedness from
10391042 // the wildcard tracking state of the node instead of from the visitor itself.
@@ -1082,6 +1085,17 @@ impl<'tcx> LocationTree {
10821085 return Err ( no_valid_exposed_references_error ( diagnostics) ) ;
10831086 } ;
10841087
1088+ let mut entry = args. data . perms . entry ( args. idx ) ;
1089+ let perm = entry. or_insert ( node. default_location_state ( ) ) ;
1090+
1091+ // We only count exposed nodes through which an access could happen.
1092+ if node. is_exposed
1093+ && perm. permission . strongest_allowed_local_access ( protected) . allows ( access_kind)
1094+ && max_local_tag. is_none_or ( |max_local_tag| max_local_tag >= node. tag )
1095+ {
1096+ has_valid_exposed = true ;
1097+ }
1098+
10851099 let Some ( relatedness) = wildcard_relatedness. to_relatedness ( ) else {
10861100 // If the access type is Either, then we do not apply any transition
10871101 // to this node, but we still update each of its children.
@@ -1090,8 +1104,6 @@ impl<'tcx> LocationTree {
10901104 return Ok ( ( ) ) ;
10911105 } ;
10921106
1093- let mut entry = args. data . perms . entry ( args. idx ) ;
1094- let perm = entry. or_insert ( node. default_location_state ( ) ) ;
10951107 // We know the exact relatedness, so we can actually do precise checks.
10961108 perm. perform_transition (
10971109 args. idx ,
@@ -1115,6 +1127,21 @@ impl<'tcx> LocationTree {
11151127 } )
11161128 } ,
11171129 ) ?;
1130+ // If there is no exposed node in this tree that allows this access, then the
1131+ // access *must* be foreign. So we check if the root of this tree would allow this
1132+ // as a foreign access, and if not, then we can error.
1133+ // In practice, all wildcard trees accept foreign accesses, but the main tree does
1134+ // not, so this catches UB when none of the nodes in the main tree allows this access.
1135+ if !has_valid_exposed
1136+ && self
1137+ . wildcard_accesses
1138+ . get ( root)
1139+ . unwrap ( )
1140+ . access_relatedness ( access_kind, /* only_foreign */ true )
1141+ . is_none ( )
1142+ {
1143+ return Err ( no_valid_exposed_references_error ( diagnostics) ) . into ( ) ;
1144+ }
11181145 interp_ok ( ( ) )
11191146 }
11201147}
0 commit comments