bevyengine / bevyengine/bevy

Inserting components is not panic-safe

Open
#20,368 0 comments 0 reactions 0 assignees View on GitHub
A-ECS C-Bug D-Unsafe I-Unsound
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.