Re: [PATCH] rust: elaborate safety requirements for `AlwaysReferenceCounted`
From: Alice Ryhl
Date: Fri May 02 2025 - 08:02:59 EST
On Fri, May 02, 2025 at 01:53:57PM +0200, Andreas Hindborg wrote:
> Clarify that implementers of `AlwaysReferenceCounted` must prevent the
> implementer from being directly initialized by users.
>
> It is a violation of the safety requirements of `AlwaysReferenceCounted` if
> its implementers can be initialized on the stack by users. Although this
> follows from the safety requirements, it is not immediately obvious.
>
> The following example demonstrates the issue. Note that the safety
> requirements for implementing `AlwaysRefCounted` and for calling
> `ARef::from_raw` are satisfied.
>
> struct Empty {}
>
> unsafe impl AlwaysRefCounted for Empty {
> fn inc_ref(&self) {}
> unsafe fn dec_ref(_obj: NonNull<Self>) {}
> }
>
> fn unsound() -> ARef<Empty> {
> use core::ptr::NonNull;
> use kernel::types::{ARef, RefCounted};
>
> let mut data = Empty {};
> let ptr = NonNull::<Empty>::new(&mut data).unwrap();
> let aref: ARef<Empty> = unsafe { ARef::from_raw(ptr) };
>
> aref
> }
I don't think it's entirely impossible to write an AlwaysRefCounted
value that can be on the stack. The type just needs a lifetime
parameter. For example, this API is not unsound:
struct MyDataStorage {
// ...
}
impl MyDataStorage {
fn as_aref(&self) -> ARef<MyData<'_>> {
unsafe { ARef::from_raw(ptr::from_ref(self).cast()) }
}
}
#[repr(transparent)]
struct MyData<'s> {
storage: MyDataStorage,
_lifetime: PhantomData<&'s MyDataStorage>,
}
unsafe impl AlwaysRefCounted for MyData<'_> {
fn inc_ref(&self) {}
unsafe fn dec_ref(_obj: NonNull<Self>) {}
}
impl Deref for MyData<'_> {
type Target = MyDataStorage;
fn deref(&self) -> &MyDataStorage {
&self.storage
}
}
Alice