@@ -110,7 +110,7 @@ impl LocationState {
110110
111111    // Helper to optimize the tree traversal. 
112112    // The optimization here consists of observing thanks to the tests 
113-     // `foreign_read_is_noop_after_write ` and `all_transitions_idempotent`, 
113+     // `foreign_read_is_noop_after_foreign_write ` and `all_transitions_idempotent`, 
114114    // that there are actually just three possible sequences of events that can occur 
115115    // in between two child accesses that produce different results. 
116116    // 
@@ -139,7 +139,7 @@ impl LocationState {
139139            let  new_access_noop = match  ( self . latest_foreign_access ,  access_kind)  { 
140140                // Previously applied transition makes the new one a guaranteed 
141141                // noop in the two following cases: 
142-                 // (1) justified by `foreign_read_is_noop_after_write ` 
142+                 // (1) justified by `foreign_read_is_noop_after_foreign_write ` 
143143                ( Some ( AccessKind :: Write ) ,  AccessKind :: Read )  => true , 
144144                // (2) justified by `all_transitions_idempotent` 
145145                ( Some ( old) ,  new)  if  old == new => true , 
@@ -670,7 +670,8 @@ impl AccessRelatedness {
670670mod  commutation_tests { 
671671    use  super :: * ; 
672672    impl  LocationState  { 
673-         pub  fn  all_without_access ( )  -> impl  Iterator < Item  = Self >  { 
673+         pub  fn  all ( )  -> impl  Iterator < Item  = Self >  { 
674+             // We keep `latest_foreign_access` at `None` as that's just a cache. 
674675            Permission :: all ( ) . flat_map ( |permission| { 
675676                [ false ,  true ] . into_iter ( ) . map ( move  |initialized| { 
676677                    Self  {  permission,  initialized,  latest_foreign_access :  None  } 
@@ -695,12 +696,12 @@ mod commutation_tests {
695696                // Any protector state works, but we can't move reads across function boundaries 
696697                // so the two read accesses occur under the same protector. 
697698                for  & protected in  & [ true ,  false ]  { 
698-                     for  loc in  LocationState :: all_without_access ( )  { 
699+                     for  loc in  LocationState :: all ( )  { 
699700                        // Apply 1 then 2. Failure here means that there is UB in the source 
700701                        // and we skip the check in the target. 
701702                        let  mut  loc12 = loc; 
702-                         let  Ok ( _)  = loc12. perform_access ( kind,  rel1,  protected)  else  {  continue ;  } ; 
703-                         let  Ok ( _)  = loc12. perform_access ( kind,  rel2,  protected)  else  {  continue ;  } ; 
703+                         let  Ok ( _)  = loc12. perform_access ( kind,  rel1,  protected)  else  {  continue  } ; 
704+                         let  Ok ( _)  = loc12. perform_access ( kind,  rel2,  protected)  else  {  continue  } ; 
704705
705706                        // If 1 followed by 2 succeeded, then 2 followed by 1 must also succeed... 
706707                        let  mut  loc21 = loc; 
@@ -718,4 +719,33 @@ mod commutation_tests {
718719            } 
719720        } 
720721    } 
722+ 
723+     #[ test]  
724+     #[ rustfmt:: skip]  
725+     // Ensure that of 2 accesses happen, one foreign and one a child, and we are protected, that we 
726+     // get UB unless they are both reads. 
727+     fn  protected_enforces_noalias ( )  { 
728+         for  rel1 in  AccessRelatedness :: all ( )  { 
729+             for  rel2 in  AccessRelatedness :: all ( )  { 
730+                 if  rel1. is_foreign ( )  == rel2. is_foreign ( )  { 
731+                     // We want to check pairs of accesses where one is foreign and one is not. 
732+                     continue ; 
733+                 } 
734+                 for  kind1 in  AccessKind :: all ( )  { 
735+                     for  kind2 in  AccessKind :: all ( )  { 
736+                         for  mut  state in  LocationState :: all ( )  { 
737+                             let  protected = true ; 
738+                             let  Ok ( _)  = state. perform_access ( kind1,  rel1,  protected)  else  {  continue  } ; 
739+                             let  Ok ( _)  = state. perform_access ( kind2,  rel2,  protected)  else  {  continue  } ; 
740+                             // If these were both allowed, it must have been two reads. 
741+                             assert ! ( 
742+                                 kind1 == AccessKind :: Read  && kind2 == AccessKind :: Read , 
743+                                 "failed to enforce noalias between two accesses that are not both reads" 
744+                             ) ; 
745+                         } 
746+                     } 
747+                 } 
748+             } 
749+         } 
750+     } 
721751} 
0 commit comments