-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Fix run_system
for adapter systems wrapping exclusive systems
#18406
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix run_system
for adapter systems wrapping exclusive systems
#18406
Conversation
…usive systems. It was calling `run_unsafe` on the adapter, which called `ExclusiveFunctionSystem::run_unsafe`.
) -> Self::Out { | ||
// SAFETY: `is_exclusive` returned true, so the caller ensured we had `&mut World` access |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This safety comment doesn't make sense to me. We never check is_exclusive in this method. My understanding here is that you've passed the safety requirements for calling world_mut
to the caller as it can't be verified here. https://docs.rs/bevy/latest/bevy/ecs/world/unsafe_world_cell/struct.UnsafeWorldCell.html#safety-1
And so need to update the safety comment on run_unsafe
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, I did update the safety comment on run_unsafe
. It now has the additional requirement that
/// - If [`System::is_exclusive`] returns `true`, then it must be valid to call
/// [`UnsafeWorldCell::world_mut`] on `world`.
What I wanted to communicate here is that because ExclusiveFunctionSystem::is_exclusive
returns true
, that clause triggered and the caller had to ensure that world_mut
was valid.
If you have ideas on how to make the wording more clear, I'm happy to update it!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll try changing it to
- // SAFETY: `is_exclusive` returned true, so the caller ensured we had `&mut World` access
+ // SAFETY: `Self::is_exclusive` returns true, so the caller is
+ // required to ensure that the it's valid to call `world_mut()`
Is that any better?
Adding to 0.16 because I'm pretty sure this worked in 0.15 and will be a regression if not fixed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just some nits, but the safety comments in multi_threaded should probably be fixed.
Ping me when the safety comments are improved and I'll merge this in. |
It should be ready now! (Sorry, I had pushed up the fixes before your message, but I always forget that I'm allowed to click "resolve conversation" myself.) |
# Objective Fix panic in `run_system` when running an exclusive system wrapped in a `PipeSystem` or `AdapterSystem`. #18076 introduced a `System::run_without_applying_deferred` method. It normally calls `System::run_unsafe`, but `ExclusiveFunctionSystem::run_unsafe` panics, so it was overridden for that type. Unfortunately, `PipeSystem::run_without_applying_deferred` still calls `PipeSystem::run_unsafe`, which can then call `ExclusiveFunctionSystem::run_unsafe` and panic. ## Solution Make `ExclusiveFunctionSystem::run_unsafe` work instead of panicking. Clarify the safety requirements that make this sound. The alternative is to override `run_without_applying_deferred` in `PipeSystem`, `CombinatorSystem`, `AdapterSystem`, `InfallibleSystemWrapper`, and `InfallibleObserverWrapper`. That seems like a lot of extra code just to preserve a confusing special case! Remove some implementations of `System::run` that are no longer necessary with this change. This slightly changes the behavior of `PipeSystem` and `CombinatorSystem`: Currently `run` will call `apply_deferred` on the first system before running the second, but after this change it will only call it after *both* systems have run. The new behavior is consistent with `run_unsafe` and `run_without_applying_deferred`, and restores the behavior prior to #11823. The panic was originally necessary because [`run_unsafe` took `&World`](https://github.com/bevyengine/bevy/pull/6083/files#diff-708dfc60ec5eef432b20a6f471357a7ea9bfb254dc2f918d5ed4a66deb0e85baR90). Now that it takes `UnsafeWorldCell`, it is possible to make it work. See also Cart's concerns at #4166 (comment), although those also predate `UnsafeWorldCell`. And see #6698 for a previous bug caused by this panic.
…utor` (#18684) # Objective Simplify code in the `SingleThreadedExecutor` by removing a special case for exclusive systems. The `SingleThreadedExecutor` runs systems without immediately applying deferred buffers. That required calling `run_unsafe()` instead of `run()`, but that would `panic` for exclusive systems, so the code also needed a special case for those. Following #18076 and #18406, we have a `run_without_applying_deferred` method that has the exact behavior we want and works on exclusive systems. ## Solution Replace the code in `SingleThreadedExecutor` that runs systems with a single call to `run_without_applying_deferred()`. Also add this as a wrapper in the `__rust_begin_short_backtrace` module to preserve the special behavior for backtraces.
…utor` (bevyengine#18684) # Objective Simplify code in the `SingleThreadedExecutor` by removing a special case for exclusive systems. The `SingleThreadedExecutor` runs systems without immediately applying deferred buffers. That required calling `run_unsafe()` instead of `run()`, but that would `panic` for exclusive systems, so the code also needed a special case for those. Following bevyengine#18076 and bevyengine#18406, we have a `run_without_applying_deferred` method that has the exact behavior we want and works on exclusive systems. ## Solution Replace the code in `SingleThreadedExecutor` that runs systems with a single call to `run_without_applying_deferred()`. Also add this as a wrapper in the `__rust_begin_short_backtrace` module to preserve the special behavior for backtraces.
Objective
Fix panic in
run_system
when running an exclusive system wrapped in aPipeSystem
orAdapterSystem
.#18076 introduced a
System::run_without_applying_deferred
method. It normally callsSystem::run_unsafe
, butExclusiveFunctionSystem::run_unsafe
panics, so it was overridden for that type. Unfortunately,PipeSystem::run_without_applying_deferred
still callsPipeSystem::run_unsafe
, which can then callExclusiveFunctionSystem::run_unsafe
and panic.Solution
Make
ExclusiveFunctionSystem::run_unsafe
work instead of panicking. Clarify the safety requirements that make this sound.The alternative is to override
run_without_applying_deferred
inPipeSystem
,CombinatorSystem
,AdapterSystem
,InfallibleSystemWrapper
, andInfallibleObserverWrapper
. That seems like a lot of extra code just to preserve a confusing special case!Remove some implementations of
System::run
that are no longer necessary with this change. This slightly changes the behavior ofPipeSystem
andCombinatorSystem
: Currentlyrun
will callapply_deferred
on the first system before running the second, but after this change it will only call it after both systems have run. The new behavior is consistent withrun_unsafe
andrun_without_applying_deferred
, and restores the behavior prior to #11823.The panic was originally necessary because
run_unsafe
took&World
. Now that it takesUnsafeWorldCell
, it is possible to make it work. See also Cart's concerns at #4166 (comment), although those also predateUnsafeWorldCell
.And see #6698 for a previous bug caused by this panic.