Skip to content

Fix UB detected by Miri when running the multi-threaded executor - #25287

Open
chescock wants to merge 1 commit into
bevyengine:mainfrom
chescock:fix-executor-ub-in-race
Open

Fix UB detected by Miri when running the multi-threaded executor#25287
chescock wants to merge 1 commit into
bevyengine:mainfrom
chescock:fix-executor-ub-in-race

Conversation

@chescock

@chescock chescock commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Objective

Fix UB detected by Miri when running the multi-threaded executor. It intermittently fails with:

error: Undefined Behavior: not granting access to tag <5526305> because that would remove [SharedReadOnly for <5518830>] which is strongly protected
   --> crates\bevy_ecs\src\schedule\executor\multi_threaded.rs:785:36
    |
785 |         let system = &mut unsafe { &mut *systems[system_index].get() }.system;
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
    |
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
    = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
help: <5526305> was created by a SharedReadWrite retag at offsets [0x0..0x80]
   --> crates\bevy_platform\src\cell\sync_unsafe_cell.rs:58:8
help: <5518830> is this argument
   --> crates\bevy_ecs\src\schedule\executor\multi_threaded.rs:334:9
    |
334 |         system: &ScheduleSystem,
    |         ^^^^^^
    = note: this is on thread `schedule::executor::multi_threaded::tests::check_spawn_exclusive_system_task_miri`
    = note: stack backtrace:

The issue is that system_completed() calls self.tick_executor();, which spawns new tasks. It may spawn a task to execute apply_deferred, which will create a &mut to systems with unapplied buffers. If that task is scheduled before system_completed() completes, then that &mut will invalidate the &ScheduleSystem parameter while it's strongly protected.

Solution

Pass the &SyncUnsafeCell<SystemWithAccess> around directly, and only convert it to a &mut SystemWithAccess when it is used. This ensures that all references have ended before the call to tick_executor(). The conversion just reinterprets the pointers and has no runtime effect, so doing it at different times should not affect performance.

@chescock chescock added C-Bug An unexpected or incorrect behavior A-ECS Entities, components, systems, and events P-Unsound A bug that results in undefined compiler behavior S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Aug 3, 2026
@github-project-automation github-project-automation Bot moved this to Needs SME Triage in ECS Aug 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-ECS Entities, components, systems, and events C-Bug An unexpected or incorrect behavior P-Unsound A bug that results in undefined compiler behavior S-Needs-Review Needs reviewer attention (from anyone!) to move forward

Projects

Status: Needs SME Triage

Development

Successfully merging this pull request may close these issues.

2 participants