Skip to content

Commit a1cd173

Browse files
committed
>:(
1 parent b6a647c commit a1cd173

File tree

4 files changed

+50
-41
lines changed

4 files changed

+50
-41
lines changed

crates/bevy_ecs/src/reflect.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -103,15 +103,17 @@ impl<C: Component + Reflect + FromWorld> FromType<C> for ReflectComponent {
103103
.entity_mut(destination_entity)
104104
.insert(destination_component);
105105
},
106-
reflect_component: |world, entity| {
106+
reflect_component: |world, entity| unsafe {
107107
world
108108
.get_entity(entity)?
109-
.get::<C>()
109+
// SAFE: lifetimes force correct usage of returned data
110+
.get_unchecked::<C>()
110111
.map(|c| c as &dyn Reflect)
111112
},
112113
reflect_component_mut: |world, entity| unsafe {
113114
world
114115
.get_entity(entity)?
116+
// SAFE: lifetimes force correct usage of returned data
115117
.get_unchecked_mut::<C>(world.last_change_tick(), world.read_change_tick())
116118
.map(|c| ReflectMut {
117119
value: c.value as &mut dyn Reflect,

crates/bevy_ecs/src/system/query.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -728,9 +728,12 @@ where
728728
.archetype_component_access
729729
.has_read(archetype_component)
730730
{
731-
entity_ref
732-
.get::<T>()
733-
.ok_or(QueryComponentError::MissingComponent)
731+
// SAFE: lifetimes enforce correct usage of returned borrow
732+
unsafe {
733+
entity_ref
734+
.get_unchecked::<T>()
735+
.ok_or(QueryComponentError::MissingComponent)
736+
}
734737
} else {
735738
Err(QueryComponentError::MissingReadAccess)
736739
}

crates/bevy_ecs/src/world/entity_ref.rs

+36-34
Original file line numberDiff line numberDiff line change
@@ -62,17 +62,26 @@ impl<'w> EntityRef<'w> {
6262
}
6363

6464
#[inline]
65-
pub fn get<T: Component>(&self) -> Option<&'w T> {
65+
pub fn get<T: Component>(&self) -> Option<&'_ T> {
66+
// SAFE: lifetimes enforce correct usage of returned borrow
67+
unsafe { self.get_unchecked::<T>() }
68+
}
69+
70+
/// This allows aliased mutability use after free bugs.
71+
/// # Safety
72+
/// - Must not be a mutable reference to the component.
73+
/// - Must not use the returned reference after the component is removed
74+
#[inline]
75+
pub unsafe fn get_unchecked<T: Component>(&self) -> Option<&'w T> {
6676
// SAFE: entity location is valid and returned component is of type T
67-
unsafe {
68-
get_component_with_type(self.world, TypeId::of::<T>(), self.entity, self.location)
69-
.map(|value| &*value.cast::<T>())
70-
}
77+
get_component_with_type(self.world, TypeId::of::<T>(), self.entity, self.location)
78+
.map(|value| &*value.cast::<T>())
7179
}
7280

81+
/// This allows aliased mutability and use after free bugs.
7382
/// # Safety
74-
/// This allows aliased mutability. You must make sure this call does not result in multiple
75-
/// mutable references to the same component
83+
/// - Must not be any other references to the component.
84+
/// - Must not use the returned reference after the component is removed.
7685
#[inline]
7786
pub unsafe fn get_unchecked_mut<T: Component>(
7887
&self,
@@ -145,39 +154,32 @@ impl<'w> EntityMut<'w> {
145154
}
146155

147156
#[inline]
148-
pub fn get<T: Component>(&self) -> Option<&'w T> {
149-
// SAFE: entity location is valid and returned component is of type T
150-
unsafe {
151-
get_component_with_type(self.world, TypeId::of::<T>(), self.entity, self.location)
152-
.map(|value| &*value.cast::<T>())
153-
}
157+
pub fn get<T: Component>(&self) -> Option<&'_ T> {
158+
// SAFE: lifetimes enforce correct usage of returned borrow
159+
unsafe { self.get_unchecked::<T>() }
154160
}
155161

156162
#[inline]
157-
pub fn get_mut<T: Component>(&mut self) -> Option<Mut<'w, T>> {
158-
// SAFE: world access is unique, entity location is valid, and returned component is of type
159-
// T
160-
unsafe {
161-
get_component_and_ticks_with_type(
162-
self.world,
163-
TypeId::of::<T>(),
164-
self.entity,
165-
self.location,
166-
)
167-
.map(|(value, ticks)| Mut {
168-
value: &mut *value.cast::<T>(),
169-
ticks: Ticks {
170-
component_ticks: &mut *ticks,
171-
last_change_tick: self.world.last_change_tick(),
172-
change_tick: self.world.change_tick(),
173-
},
174-
})
175-
}
163+
pub fn get_mut<T: Component>(&mut self) -> Option<Mut<'_, T>> {
164+
// SAFE: world access is unique, and lifetimes enforce correct usage of returned borrow
165+
unsafe { self.get_unchecked_mut::<T>() }
166+
}
167+
168+
/// This allows aliased mutability use after free bugs.
169+
/// # Safety
170+
/// - Must not be a mutable reference to the component.
171+
/// - Must not use the returned reference after the component is removed
172+
#[inline]
173+
pub unsafe fn get_unchecked<T: Component>(&self) -> Option<&'w T> {
174+
// SAFE: entity location is valid and returned component is of type T
175+
get_component_with_type(self.world, TypeId::of::<T>(), self.entity, self.location)
176+
.map(|value| &*value.cast::<T>())
176177
}
177178

179+
/// This allows aliased mutability and use after free bugs.
178180
/// # Safety
179-
/// This allows aliased mutability. You must make sure this call does not result in multiple
180-
/// mutable references to the same component
181+
/// - Must not be any other references to the component.
182+
/// - Must not use the returned reference after the component is removed.
181183
#[inline]
182184
pub unsafe fn get_unchecked_mut<T: Component>(&self) -> Option<Mut<'w, T>> {
183185
get_component_and_ticks_with_type(self.world, TypeId::of::<T>(), self.entity, self.location)

crates/bevy_ecs/src/world/mod.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,8 @@ impl World {
416416
/// ```
417417
#[inline]
418418
pub fn get<T: Component>(&self, entity: Entity) -> Option<&T> {
419-
self.get_entity(entity)?.get()
419+
// SAFE: lifetimes enforce correct usage of returned borrow
420+
unsafe { self.get_entity(entity)?.get_unchecked::<T>() }
420421
}
421422

422423
/// Retrieves a mutable reference to the given `entity`'s [Component] of the given type.
@@ -439,7 +440,8 @@ impl World {
439440
/// ```
440441
#[inline]
441442
pub fn get_mut<T: Component>(&mut self, entity: Entity) -> Option<Mut<T>> {
442-
self.get_entity_mut(entity)?.get_mut()
443+
// SAFE: lifetimes enforce correct usage of returned borrow
444+
unsafe { self.get_entity_mut(entity)?.get_unchecked_mut::<T>() }
443445
}
444446

445447
/// Despawns the given `entity`, if it exists. This will also remove all of the entity's

0 commit comments

Comments
 (0)