Inserting components is not panic-safe
- Dominant language
- Rust
- Stars
- 48.2k
- Forks
- 4.8k
- Avg merge
- 3d 16h
- Merged PRs (30d)
- 171
Description
## Bevy version
f96eaa4a and 0.16
## What you did
```rs
use bevy_ecs::prelude::*;
#[derive(Component)]
struct A(&'static u8);
fn panics() -> A {
// Just to avoid printing the panic message, but any panic!() works
std::panic::resume_unwind(Box::new(()));
}
#[derive(Component)]
#[require(A = panics())]
struct B;
let mut world = World::new();
let mut e = world.spawn_empty();
std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
e.insert(B);
}));
// The EntityWorldMut thinks it's still at the old location
assert!(!e.contains::());
let id = e.id();
let e = world.entity_mut(id);
// But after refetching the location it thinks it's at the new location, but A is not initialized.
println!("{}", e.get::().unwrap().0);
```
## What went wrong
The program segfaulted when trying to read from the reference in the `A` component that did not get initialized.
Contributor guide
Research direction
Start by running the provided reproduction around World::spawn_empty, EntityWorldMut::insert, and std::panic::catch_unwind. Trace how the required A component is initialized when inserting B panics; done means the panic cannot leave entity locations inconsistent or expose an uninitialized A component.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- game-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100