From 3fba34c9e636c4d0e552e0efc49c29243a5c3800 Mon Sep 17 00:00:00 2001 From: JoJoJet <21144246+JoJoJet@users.noreply.github.com> Date: Mon, 12 Jun 2023 21:17:40 -0400 Subject: [PATCH] Require read-only queries in `QueryState::par_iter` (#8832) # Objective The method `QueryState::par_iter` does not currently force the query to be read-only. This means you can unsoundly mutate a world through an immutable reference in safe code. ```rust fn bad_system(world: &World, mut query: Local>) { query.par_iter(world).for_each_mut(|mut x| *x = unsoundness); } ``` ## Solution Use read-only versions of the `WorldQuery` types. --- ## Migration Guide The function `QueryState::par_iter` now forces any world accesses to be read-only, similar to how `QueryState::iter` works. Any code that previously mutated the world using this method was *unsound*. If you need to mutate the world, use `par_iter_mut` instead. --- crates/bevy_ecs/src/query/state.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/query/state.rs b/crates/bevy_ecs/src/query/state.rs index 16a0ea6c9d..d2bc1cc846 100644 --- a/crates/bevy_ecs/src/query/state.rs +++ b/crates/bevy_ecs/src/query/state.rs @@ -865,11 +865,14 @@ impl QueryState { /// /// [`par_iter_mut`]: Self::par_iter_mut #[inline] - pub fn par_iter<'w, 's>(&'s mut self, world: &'w World) -> QueryParIter<'w, 's, Q, F> { + pub fn par_iter<'w, 's>( + &'s mut self, + world: &'w World, + ) -> QueryParIter<'w, 's, Q::ReadOnly, F::ReadOnly> { self.update_archetypes(world); QueryParIter { world, - state: self, + state: self.as_readonly(), last_run: world.last_change_tick(), this_run: world.read_change_tick(), batching_strategy: BatchingStrategy::new(),