From f8b046f0ca8d09b5bd057d94dbd4fc3df02c64ce Mon Sep 17 00:00:00 2001 From: Zicklag Date: Mon, 23 Oct 2023 16:35:57 +0000 Subject: [PATCH] fix: fix soundness bug allowing you to extend borrows of atomic resources past its guard. (#247) --- framework_crates/bones_ecs/src/resources.rs | 14 ++++++++++++-- framework_crates/bones_schema/src/ptr.rs | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/framework_crates/bones_ecs/src/resources.rs b/framework_crates/bones_ecs/src/resources.rs index f79e88ece8..21602a41de 100644 --- a/framework_crates/bones_ecs/src/resources.rs +++ b/framework_crates/bones_ecs/src/resources.rs @@ -51,7 +51,7 @@ impl UntypedAtomicResource { pub fn borrow(&self) -> AtomicSchemaRef { let (reference, borrow) = Ref::into_split(self.cell.borrow()); // SOUND: we keep the borrow along with the reference so that the pointer remains valid. - let schema_ref = unsafe { reference.as_ref() }.as_ref(); + let schema_ref = NoClone(unsafe { reference.as_ref() }.as_ref()); AtomicSchemaRef { schema_ref, borrow } } @@ -77,11 +77,21 @@ impl UntypedAtomicResource { } } +/// Wrapper type that prevents cloning or copying the inner type. +#[derive(Deref, DerefMut)] +pub struct NoClone(T); + /// An atomic borrow of a [`SchemaRef`]. #[derive(Deref)] pub struct AtomicSchemaRef<'a> { + /// This is wrappwed in a [`NoClone`] because of the limitations of the deref trait. + /// We would prefer to have deref return a [`SchemaRef`] with an appropriate lifetime, + /// that indicates it borrows from the [`AtomicSchemaRef`], but since deref must return + /// a normal reference, instead we return a reference to the `SchemaRef` wrapped inside + /// a [`NoClone`] to prevent copying the [`SchemaRef`] out of dereference with a lifetime + /// that outlives the atomicborrow. #[deref] - schema_ref: SchemaRef<'a>, + schema_ref: NoClone>, borrow: AtomicBorrow<'a>, } diff --git a/framework_crates/bones_schema/src/ptr.rs b/framework_crates/bones_schema/src/ptr.rs index a626fd1f02..b10447b402 100644 --- a/framework_crates/bones_schema/src/ptr.rs +++ b/framework_crates/bones_schema/src/ptr.rs @@ -18,7 +18,7 @@ use bones_utils::{parking_lot::RwLock, prelude::*}; /// An untyped reference that knows the [`Schema`] of the pointee and that can be cast to a matching /// type. -#[derive(Clone)] +#[derive(Clone, Copy)] pub struct SchemaRef<'pointer> { ptr: Ptr<'pointer>, schema: &'static Schema,