From 8308ad08a2d0903343368bece912878920d79a4b Mon Sep 17 00:00:00 2001 From: Periwink Date: Tue, 25 Jun 2024 19:54:50 -0400 Subject: [PATCH] AnyOf soundness fix (#14013) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # 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 Co-authored-by: Martín Maita <47983254+mnmaita@users.noreply.github.com> --- crates/bevy_ecs/src/query/fetch.rs | 14 +++++--- crates/bevy_ecs/src/system/mod.rs | 53 ++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 5 deletions(-) diff --git a/crates/bevy_ecs/src/query/fetch.rs b/crates/bevy_ecs/src/query/fetch.rs index 2ebf95cdea..2700fe3ac4 100644 --- a/crates/bevy_ecs/src/query/fetch.rs +++ b/crates/bevy_ecs/src/query/fetch.rs @@ -1862,16 +1862,20 @@ macro_rules! impl_anytuple_fetch { } fn update_component_access(state: &Self::State, _access: &mut FilteredAccess) { - 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 { diff --git a/crates/bevy_ecs/src/system/mod.rs b/crates/bevy_ecs/src/system/mod.rs index b41255194c..9ae9f2587d 100644 --- a/crates/bevy_ecs/src/system/mod.rs +++ b/crates/bevy_ecs/src/system/mod.rs @@ -556,6 +556,51 @@ mod tests { run_system(&mut world, sys); } + #[test] + fn any_of_working() { + fn sys(_: Query>) {} + 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>) {} + 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>) {} + 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)>>) {} + let mut world = World::default(); + run_system(&mut world, sys); + } + + #[test] + fn any_of_with_entity_and_mut() { + fn sys(_: Query>) {} + let mut world = World::default(); + run_system(&mut world, sys); + } + + #[test] + fn any_of_with_empty_and_mut() { + fn sys(_: Query>) {} + 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>) {} + 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>) {}