AnyOf soundness fix (#14013)
# Objective Fixes https://github.com/bevyengine/bevy/issues/13993 PR inspired by https://github.com/bevyengine/bevy/pull/14007 to accomplish the same thing, but maybe in a clearer fashion. @Gingeh feel free to take my changes and add them to your PR, I don't want to steal any credit --------- Co-authored-by: Gingeh <39150378+Gingeh@users.noreply.github.com> Co-authored-by: Bob Gardner <rgardner@inworld.ai> Co-authored-by: Martín Maita <47983254+mnmaita@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									336fddb101
								
							
						
					
					
						commit
						8308ad08a2
					
				| @ -1862,16 +1862,20 @@ macro_rules! impl_anytuple_fetch { | ||||
|             } | ||||
| 
 | ||||
|             fn update_component_access(state: &Self::State, _access: &mut FilteredAccess<ComponentId>) { | ||||
|                 let ($($name,)*) = state; | ||||
| 
 | ||||
|                 let mut _new_access = _access.clone(); | ||||
| 
 | ||||
|                 // update the access (add the read/writes)
 | ||||
|                 <($(Option<$name>,)*)>::update_component_access(state, _access); | ||||
| 
 | ||||
|                 // update the filters (Or<(With<$name>,)>)
 | ||||
|                 let ($($name,)*) = state; | ||||
|                 let mut _not_first = false; | ||||
|                 $( | ||||
|                     if _not_first { | ||||
|                         let mut intermediate = _access.clone(); | ||||
|                         // we use an intermediate access because we only want to update the filters, not the access
 | ||||
|                         let mut intermediate = FilteredAccess::default(); | ||||
|                         $name::update_component_access($name, &mut intermediate); | ||||
|                         _new_access.append_or(&intermediate); | ||||
|                         _new_access.extend_access(&intermediate); | ||||
|                     } else { | ||||
|                         $name::update_component_access($name, &mut _new_access); | ||||
|                         _new_access.required = _access.required.clone(); | ||||
| @ -1879,7 +1883,7 @@ macro_rules! impl_anytuple_fetch { | ||||
|                     } | ||||
|                 )* | ||||
| 
 | ||||
|                 *_access = _new_access; | ||||
|                 _access.filter_sets = _new_access.filter_sets; | ||||
|             } | ||||
|             #[allow(unused_variables)] | ||||
|             fn init_state(world: &mut World) -> Self::State { | ||||
|  | ||||
| @ -556,6 +556,51 @@ mod tests { | ||||
|         run_system(&mut world, sys); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn any_of_working() { | ||||
|         fn sys(_: Query<AnyOf<(&mut A, &B)>>) {} | ||||
|         let mut world = World::default(); | ||||
|         run_system(&mut world, sys); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     #[should_panic = "&bevy_ecs::system::tests::A conflicts with a previous access in this query."] | ||||
|     fn any_of_with_mut_and_ref() { | ||||
|         fn sys(_: Query<AnyOf<(&mut A, &A)>>) {} | ||||
|         let mut world = World::default(); | ||||
|         run_system(&mut world, sys); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     #[should_panic = "&mut bevy_ecs::system::tests::A conflicts with a previous access in this query."] | ||||
|     fn any_of_with_ref_and_mut() { | ||||
|         fn sys(_: Query<AnyOf<(&A, &mut A)>>) {} | ||||
|         let mut world = World::default(); | ||||
|         run_system(&mut world, sys); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     #[should_panic = "&bevy_ecs::system::tests::A conflicts with a previous access in this query."] | ||||
|     fn any_of_with_mut_and_option() { | ||||
|         fn sys(_: Query<AnyOf<(&mut A, Option<&A>)>>) {} | ||||
|         let mut world = World::default(); | ||||
|         run_system(&mut world, sys); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn any_of_with_entity_and_mut() { | ||||
|         fn sys(_: Query<AnyOf<(Entity, &mut A)>>) {} | ||||
|         let mut world = World::default(); | ||||
|         run_system(&mut world, sys); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn any_of_with_empty_and_mut() { | ||||
|         fn sys(_: Query<AnyOf<((), &mut A)>>) {} | ||||
|         let mut world = World::default(); | ||||
|         run_system(&mut world, sys); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     #[should_panic = "error[B0001]"] | ||||
|     fn any_of_has_no_filter_with() { | ||||
| @ -564,6 +609,14 @@ mod tests { | ||||
|         run_system(&mut world, sys); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     #[should_panic = "&mut bevy_ecs::system::tests::A conflicts with a previous access in this query."] | ||||
|     fn any_of_with_conflicting() { | ||||
|         fn sys(_: Query<AnyOf<(&mut A, &mut A)>>) {} | ||||
|         let mut world = World::default(); | ||||
|         run_system(&mut world, sys); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn any_of_has_filter_with_when_both_have_it() { | ||||
|         fn sys(_: Query<(AnyOf<(&A, &A)>, &mut B)>, _: Query<&mut B, Without<A>>) {} | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Periwink
						Periwink