From 0dc2ec0159e3042dd25d2989c47d383bb0ac54fc Mon Sep 17 00:00:00 2001 From: Ellen Date: Thu, 15 Apr 2021 04:26:07 +0100 Subject: [PATCH] Fix unsoundness in query component access --- crates/bevy_ecs/src/lib.rs | 7 +++++++ crates/bevy_ecs/src/query/fetch.rs | 8 ++++++++ crates/bevy_ecs/src/query/filter.rs | 4 ++++ 3 files changed, 19 insertions(+) diff --git a/crates/bevy_ecs/src/lib.rs b/crates/bevy_ecs/src/lib.rs index a85e95a2a7f9a..4db81495b3866 100644 --- a/crates/bevy_ecs/src/lib.rs +++ b/crates/bevy_ecs/src/lib.rs @@ -1071,6 +1071,13 @@ mod tests { world.query::<(&A, &mut A)>(); } + #[test] + #[should_panic] + fn mut_and_ref_query_panic() { + let mut world = World::new(); + world.query::<(&mut A, &A)>(); + } + #[test] #[should_panic] fn mut_and_mut_query_panic() { diff --git a/crates/bevy_ecs/src/query/fetch.rs b/crates/bevy_ecs/src/query/fetch.rs index 91f423be28725..0350651f6808f 100644 --- a/crates/bevy_ecs/src/query/fetch.rs +++ b/crates/bevy_ecs/src/query/fetch.rs @@ -206,6 +206,10 @@ unsafe impl FetchState for ReadState { } fn update_component_access(&self, access: &mut FilteredAccess) { + if access.access().has_write(self.component_id) { + panic!("&{} conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.", + std::any::type_name::()); + } access.add_read(self.component_id) } @@ -656,6 +660,10 @@ unsafe impl FetchState for ChangeTrackersState { } fn update_component_access(&self, access: &mut FilteredAccess) { + if access.access().has_write(self.component_id) { + panic!("ChangeTrackers<{}> conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.", + std::any::type_name::()); + } access.add_read(self.component_id) } diff --git a/crates/bevy_ecs/src/query/filter.rs b/crates/bevy_ecs/src/query/filter.rs index ed611b5b7b323..d745f456d59ce 100644 --- a/crates/bevy_ecs/src/query/filter.rs +++ b/crates/bevy_ecs/src/query/filter.rs @@ -501,6 +501,10 @@ macro_rules! impl_tick_filter { #[inline] fn update_component_access(&self, access: &mut FilteredAccess) { + if access.access().has_write(self.component_id) { + panic!("$state_name<{}> conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.", + std::any::type_name::()); + } access.add_read(self.component_id); }