-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Description
Bevy version
0.16 and commit f964ee1
What you did
I implemented Component::register_required_components
by using a different ComponentsRegistrator
instance than the one provided when registering required components in the given RequiredComponents
.
use bevy_ecs::prelude::*;
struct A;
impl Component for A {
const STORAGE_TYPE: bevy_ecs::component::StorageType =
bevy_ecs::component::StorageType::Table;
type Mutability = bevy_ecs::component::Mutable;
fn register_required_components(
_component_id: bevy_ecs::component::ComponentId,
components: &mut bevy_ecs::component::ComponentsRegistrator,
required_components: &mut bevy_ecs::component::RequiredComponents,
_inheritance_depth: u16,
_recursion_check_stack: &mut Vec<bevy_ecs::component::ComponentId>,
) {
#[derive(Component)]
struct AFake;
#[derive(Component)]
struct BFake(usize);
components.register_component::<B>();
let mut world = World::new();
let mut wrong_components = world.components_registrator();
wrong_components.register_component::<AFake>();
required_components.register::<BFake>(&mut wrong_components, || BFake(0x1), 0);
}
}
#[derive(Component)]
struct B(&'static u8);
let mut world = World::new();
let e = world.spawn(A).get::<B>().unwrap().0;
println!("{e}"); // will try to dereference the address 0x1
What went wrong
The code was accepted and at runtime a component is initialized with the wrong type, leading to UB.
Additional informations
To be sound RequiredComponents
should require all required components to be registered in the Components
/ComponentsRegistrator
instance associated with it. This is however broken by the fact that we expect safe code to pass the correct instance of ComponentsRegistrator
to RequiredComponents
. This could be solved by replacing them with a struct that wraps both of them and ensures the methods on RequiredComponents
are called with the right ComponentsRegistrator
.
Found while implementing #20110