lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <Zq8lnBvgqXAk1B5e@boqun-archlinux>
Date: Sat, 3 Aug 2024 23:54:20 -0700
From: Boqun Feng <boqun.feng@...il.com>
To: Danilo Krummrich <dakr@...nel.org>
Cc: ojeda@...nel.org, alex.gaynor@...il.com, wedsonaf@...il.com,
	gary@...yguo.net, bjorn3_gh@...tonmail.com, benno.lossin@...ton.me,
	a.hindborg@...sung.com, aliceryhl@...gle.com,
	akpm@...ux-foundation.org, daniel.almeida@...labora.com,
	faith.ekstrand@...labora.com, boris.brezillon@...labora.com,
	lina@...hilina.net, mcanal@...lia.com, zhiw@...dia.com,
	acurrid@...dia.com, cjia@...dia.com, jhubbard@...dia.com,
	airlied@...hat.com, ajanulgu@...hat.com, lyude@...hat.com,
	linux-kernel@...r.kernel.org, rust-for-linux@...r.kernel.org,
	linux-mm@...ck.org
Subject: Re: [PATCH v3 08/25] rust: types: implement `Unique<T>`

On Thu, Aug 01, 2024 at 02:02:07AM +0200, Danilo Krummrich wrote:
> Implement the `Unique` type as a prerequisite for `Box` and `Vec`
> introduced in subsequent patches.
> 
> `Unique` serves as wrapper around a `NonNull`, but indicates that the
> possessor of this wrapper owns the referent.
> 
> This type already exists in Rust's core library, but, unfortunately, is
> exposed as unstable API and hence shouldn't be used in the kernel.
> 
> This implementation of `Unique` is almost identical, but mostly stripped
> down to the functionality we need for `Box` and `Vec`. Additionally, all
> unstable features are removed and / or replaced by stable ones.
> 
> Signed-off-by: Danilo Krummrich <dakr@...nel.org>

If I understand correctly, `Unique` does nothing unless the compiler
supports putting noalias at the corresponding IRs. If so, should this
depend on whether Rust compiler supports using `Unique` outside std
libraries?

Regards,
Boqun

> ---
>  rust/kernel/types.rs | 183 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 183 insertions(+)
> 
> diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
> index bd189d646adb..7cf89067b5fc 100644
> --- a/rust/kernel/types.rs
> +++ b/rust/kernel/types.rs
> @@ -473,3 +473,186 @@ unsafe impl AsBytes for str {}
>  // does not have any uninitialized portions either.
>  unsafe impl<T: AsBytes> AsBytes for [T] {}
>  unsafe impl<T: AsBytes, const N: usize> AsBytes for [T; N] {}
> +
> +/// A wrapper around a raw non-null `*mut T` that indicates that the possessor
> +/// of this wrapper owns the referent. Useful for building abstractions like
> +/// `Box<T>`, `Vec<T>`, `String`, and `HashMap<K, V>`.
> +///
> +/// Unlike `*mut T`, `Unique<T>` behaves "as if" it were an instance of `T`.
> +/// It implements `Send`/`Sync` if `T` is `Send`/`Sync`. It also implies
> +/// the kind of strong aliasing guarantees an instance of `T` can expect:
> +/// the referent of the pointer should not be modified without a unique path to
> +/// its owning Unique.
> +///
> +/// If you're uncertain of whether it's correct to use `Unique` for your purposes,
> +/// consider using `NonNull`, which has weaker semantics.
> +///
> +/// Unlike `*mut T`, the pointer must always be non-null, even if the pointer
> +/// is never dereferenced. This is so that enums may use this forbidden value
> +/// as a discriminant -- `Option<Unique<T>>` has the same size as `Unique<T>`.
> +/// However the pointer may still dangle if it isn't dereferenced.
> +///
> +/// Unlike `*mut T`, `Unique<T>` is covariant over `T`. This should always be correct
> +/// for any type which upholds Unique's aliasing requirements.
> +#[repr(transparent)]
> +pub struct Unique<T: ?Sized> {
> +    pointer: NonNull<T>,
> +    // NOTE: this marker has no consequences for variance, but is necessary
> +    // for dropck to understand that we logically own a `T`.
> +    //
> +    // For details, see:
> +    // https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md#phantom-data
> +    _marker: PhantomData<T>,
> +}
> +
> +/// `Unique` pointers are `Send` if `T` is `Send` because the data they
> +/// reference is unaliased. Note that this aliasing invariant is
> +/// unenforced by the type system; the abstraction using the
> +/// `Unique` must enforce it.
> +unsafe impl<T: Send + ?Sized> Send for Unique<T> {}
> +
> +/// `Unique` pointers are `Sync` if `T` is `Sync` because the data they
> +/// reference is unaliased. Note that this aliasing invariant is
> +/// unenforced by the type system; the abstraction using the
> +/// `Unique` must enforce it.
> +unsafe impl<T: Sync + ?Sized> Sync for Unique<T> {}
> +
> +impl<T: Sized> Unique<T> {
> +    /// Creates a new `Unique` that is dangling, but well-aligned.
> +    ///
> +    /// This is useful for initializing types which lazily allocate, like
> +    /// `Vec::new` does.
> +    ///
> +    /// Note that the pointer value may potentially represent a valid pointer to
> +    /// a `T`, which means this must not be used as a "not yet initialized"
> +    /// sentinel value. Types that lazily allocate must track initialization by
> +    /// some other means.
> +    #[must_use]
> +    #[inline]
> +    pub const fn dangling() -> Self {
> +        Unique {
> +            pointer: NonNull::dangling(),
> +            _marker: PhantomData,
> +        }
> +    }
> +}
> +
> +impl<T: ?Sized> Unique<T> {
> +    /// Creates a new `Unique`.
> +    ///
> +    /// # Safety
> +    ///
> +    /// `ptr` must be non-null.
> +    #[inline]
> +    pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
> +        // SAFETY: the caller must guarantee that `ptr` is non-null.
> +        unsafe {
> +            Unique {
> +                pointer: NonNull::new_unchecked(ptr),
> +                _marker: PhantomData,
> +            }
> +        }
> +    }
> +
> +    /// Creates a new `Unique` if `ptr` is non-null.
> +    #[allow(clippy::manual_map)]
> +    #[inline]
> +    pub fn new(ptr: *mut T) -> Option<Self> {
> +        if let Some(pointer) = NonNull::new(ptr) {
> +            Some(Unique {
> +                pointer,
> +                _marker: PhantomData,
> +            })
> +        } else {
> +            None
> +        }
> +    }
> +
> +    /// Acquires the underlying `*mut` pointer.
> +    #[must_use = "`self` will be dropped if the result is not used"]
> +    #[inline]
> +    pub const fn as_ptr(self) -> *mut T {
> +        self.pointer.as_ptr()
> +    }
> +
> +    /// Dereferences the content.
> +    ///
> +    /// The resulting lifetime is bound to self so this behaves "as if"
> +    /// it were actually an instance of T that is getting borrowed. If a longer
> +    /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`.
> +    ///
> +    /// # Safety
> +    ///
> +    /// Safety requirements for this function are inherited from [NonNull::as_ref].
> +    ///
> +    #[must_use]
> +    #[inline]
> +    pub const unsafe fn as_ref(&self) -> &T {
> +        // SAFETY: the caller must guarantee that `self` meets all the
> +        // requirements for a reference.
> +        unsafe { self.pointer.as_ref() }
> +    }
> +
> +    /// Mutably dereferences the content.
> +    ///
> +    /// The resulting lifetime is bound to self so this behaves "as if"
> +    /// it were actually an instance of T that is getting borrowed. If a longer
> +    /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`.
> +    ///
> +    /// # Safety
> +    ///
> +    /// Safety requirements for this function are inherited from [NonNull::as_mut].
> +    #[must_use]
> +    #[inline]
> +    pub unsafe fn as_mut(&mut self) -> &mut T {
> +        // SAFETY: the caller must guarantee that `self` meets all the
> +        // requirements for a mutable reference.
> +        unsafe { self.pointer.as_mut() }
> +    }
> +
> +    /// Casts to a pointer of another type.
> +    #[must_use = "`self` will be dropped if the result is not used"]
> +    #[inline]
> +    pub fn cast<U>(self) -> Unique<U> {
> +        Unique::from(self.pointer.cast())
> +    }
> +
> +    /// Acquires the underlying `*mut` pointer.
> +    #[must_use = "`self` will be dropped if the result is not used"]
> +    #[inline]
> +    pub const fn as_non_null(self) -> NonNull<T> {
> +        self.pointer
> +    }
> +}
> +
> +impl<T: ?Sized> Clone for Unique<T> {
> +    #[inline]
> +    fn clone(&self) -> Self {
> +        *self
> +    }
> +}
> +
> +impl<T: ?Sized> Copy for Unique<T> {}
> +
> +impl<T: ?Sized> From<&mut T> for Unique<T> {
> +    /// Converts a `&mut T` to a `Unique<T>`.
> +    ///
> +    /// This conversion is infallible since references cannot be null.
> +    #[inline]
> +    fn from(reference: &mut T) -> Self {
> +        Self::from(NonNull::from(reference))
> +    }
> +}
> +
> +impl<T: ?Sized> From<NonNull<T>> for Unique<T> {
> +    /// Converts a `NonNull<T>` to a `Unique<T>`.
> +    ///
> +    /// This conversion is infallible since `NonNull` cannot be null.
> +    #[inline]
> +    fn from(pointer: NonNull<T>) -> Self {
> +        Unique {
> +            pointer,
> +            _marker: PhantomData,
> +        }
> +    }
> +}
> -- 
> 2.45.2
> 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ