Crash when second window is closed first in multiple_windows example.
- Dominant language
- Rust
- Stars
- 48.2k
- Forks
- 4.8k
- Avg merge
- 3d 22h
- Merged PRs (30d)
- 161
Description
## Bevy version
0.16.0
## Relevant system information
- Rust version: `rustc 1.85.0 (4d91de4e4 2025-02-17)`
- Operating system: macOS Sequoia 15.5 (24F74)
- Graphics adapter info:
```ignore
`AdapterInfo { name: "Apple M1", vendor: 0, device: 0, device_type: IntegratedGpu, driver: "", driver_info: "", backend: Metal }`
```
## What I did
Ran the `multiple_windows` example provided in the bevy repository.
Steps to reproduce:
1. Run the example.
2. Close the second window before the primary window.
## What went wrong
- Expected behavior:
The application should handle the second window closing gracefully and continue running with the first window.
- Actual behavior:
The application crashes immediately when the second window is closed first. No crash occurs when the first window is closed before the second.
## Additional information
- After investigation, I tracked the crash down to the `AccessKitAdapter` removal logic in the `window_closed` system of the `accessibility` module in the `bevy_winit` crate.
- As a workaround, I delayed the `AccessKitAdapter` removal in the `window_closed` system by 1 frame, which prevented the crash. However, this is admittedly a hacky solution and likely not ideal for upstream.
```rust
fn window_closed(
// Removed
// mut adapters: NonSendMut,
// Added
mut removal_queue: ResMut,
mut handlers: ResMut,
mut events: EventReader,
) {
for WindowClosed { window, .. } in events.read() {
// Removed
// adapters.remove(window);
// Added
removal_queue.to_remove.push(*window);
removal_queue.frame_delay = 1;
handlers.remove(window);
}
}
impl Plugin for AccessKitPlugin {
fn build(&self, app: &mut App) {
app.init_non_send_resource::()
.init_resource::()
// Added
.init_resource::()
.add_event::()
.add_systems(
PostUpdate,
(
poll_receivers,
update_accessibility_nodes.run_if(should_update_accessibility_nodes),
window_closed
.before(poll_receivers)
.before(update_accessibility_nodes),
// Added
delayed_adapter_removal.after(window_closed),
)
.in_set(AccessibilitySystem::Update),
);
}
}
// Added
#[derive(Resource, Default)]
struct AdapterRemovalQueue {
to_remove: Vec,
frame_delay: usize,
}
// Added
fn delayed_adapter_removal(
mut adapters: NonSendMut,
mut removal_queue: ResMut,
) {
if removal_queue.frame_delay > 0 {
removal_queue.frame_delay -= 1;
return;
}
for window in removal_queue.to_remove.drain(..) {
println!("Removing adapter after delay for {:?}", window);
adapters.remove(&window);
}
}
```
Contributor guide
Assessment
This issue has not been assessed yet.