rust: types: add FOREIGN_ALIGN to ForeignOwnable

The current implementation of `ForeignOwnable` is leaking the type of the
opaque pointer to consumers of the API. This allows consumers of the opaque
pointer to rely on the information that can be extracted from the pointer
type.

To prevent this, change the API to the version suggested by Maira
Canal (link below): Remove `ForeignOwnable::PointedTo` in favor of a
constant, which specifies the alignment of the pointers returned by
`into_foreign`.

With this change, `ArcInner` no longer needs `pub` visibility, so change it
to private.

Suggested-by: Alice Ryhl <aliceryhl@google.com>
Suggested-by: Maíra Canal <mcanal@igalia.com>
Link: https://lore.kernel.org/r/20240309235927.168915-3-mcanal@igalia.com
Acked-by: Danilo Krummrich <dakr@kernel.org>
Reviewed-by: Benno Lossin <lossin@kernel.org>
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20250612-pointed-to-v3-1-b009006d86a1@kernel.org
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
Andreas Hindborg 2025-06-12 15:09:43 +02:00 committed by Miguel Ojeda
parent b6f885060e
commit 12717ebeff
7 changed files with 70 additions and 63 deletions

View File

@ -15,6 +15,7 @@
use core::ptr::NonNull; use core::ptr::NonNull;
use core::result::Result; use core::result::Result;
use crate::ffi::c_void;
use crate::init::InPlaceInit; use crate::init::InPlaceInit;
use crate::types::ForeignOwnable; use crate::types::ForeignOwnable;
use pin_init::{InPlaceWrite, Init, PinInit, ZeroableOption}; use pin_init::{InPlaceWrite, Init, PinInit, ZeroableOption};
@ -398,70 +399,74 @@ fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
} }
} }
// SAFETY: The `into_foreign` function returns a pointer that is well-aligned. // SAFETY: The pointer returned by `into_foreign` comes from a well aligned
// pointer to `T`.
unsafe impl<T: 'static, A> ForeignOwnable for Box<T, A> unsafe impl<T: 'static, A> ForeignOwnable for Box<T, A>
where where
A: Allocator, A: Allocator,
{ {
type PointedTo = T; const FOREIGN_ALIGN: usize = core::mem::align_of::<T>();
type Borrowed<'a> = &'a T; type Borrowed<'a> = &'a T;
type BorrowedMut<'a> = &'a mut T; type BorrowedMut<'a> = &'a mut T;
fn into_foreign(self) -> *mut Self::PointedTo { fn into_foreign(self) -> *mut c_void {
Box::into_raw(self) Box::into_raw(self).cast()
} }
unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self { unsafe fn from_foreign(ptr: *mut c_void) -> Self {
// SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
// call to `Self::into_foreign`. // call to `Self::into_foreign`.
unsafe { Box::from_raw(ptr) } unsafe { Box::from_raw(ptr.cast()) }
} }
unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> &'a T { unsafe fn borrow<'a>(ptr: *mut c_void) -> &'a T {
// SAFETY: The safety requirements of this method ensure that the object remains alive and // SAFETY: The safety requirements of this method ensure that the object remains alive and
// immutable for the duration of 'a. // immutable for the duration of 'a.
unsafe { &*ptr } unsafe { &*ptr.cast() }
} }
unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> &'a mut T { unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> &'a mut T {
let ptr = ptr.cast();
// SAFETY: The safety requirements of this method ensure that the pointer is valid and that // SAFETY: The safety requirements of this method ensure that the pointer is valid and that
// nothing else will access the value for the duration of 'a. // nothing else will access the value for the duration of 'a.
unsafe { &mut *ptr } unsafe { &mut *ptr }
} }
} }
// SAFETY: The `into_foreign` function returns a pointer that is well-aligned. // SAFETY: The pointer returned by `into_foreign` comes from a well aligned
// pointer to `T`.
unsafe impl<T: 'static, A> ForeignOwnable for Pin<Box<T, A>> unsafe impl<T: 'static, A> ForeignOwnable for Pin<Box<T, A>>
where where
A: Allocator, A: Allocator,
{ {
type PointedTo = T; const FOREIGN_ALIGN: usize = core::mem::align_of::<T>();
type Borrowed<'a> = Pin<&'a T>; type Borrowed<'a> = Pin<&'a T>;
type BorrowedMut<'a> = Pin<&'a mut T>; type BorrowedMut<'a> = Pin<&'a mut T>;
fn into_foreign(self) -> *mut Self::PointedTo { fn into_foreign(self) -> *mut c_void {
// SAFETY: We are still treating the box as pinned. // SAFETY: We are still treating the box as pinned.
Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }) Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }).cast()
} }
unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self { unsafe fn from_foreign(ptr: *mut c_void) -> Self {
// SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
// call to `Self::into_foreign`. // call to `Self::into_foreign`.
unsafe { Pin::new_unchecked(Box::from_raw(ptr)) } unsafe { Pin::new_unchecked(Box::from_raw(ptr.cast())) }
} }
unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> Pin<&'a T> { unsafe fn borrow<'a>(ptr: *mut c_void) -> Pin<&'a T> {
// SAFETY: The safety requirements for this function ensure that the object is still alive, // SAFETY: The safety requirements for this function ensure that the object is still alive,
// so it is safe to dereference the raw pointer. // so it is safe to dereference the raw pointer.
// The safety requirements of `from_foreign` also ensure that the object remains alive for // The safety requirements of `from_foreign` also ensure that the object remains alive for
// the lifetime of the returned value. // the lifetime of the returned value.
let r = unsafe { &*ptr }; let r = unsafe { &*ptr.cast() };
// SAFETY: This pointer originates from a `Pin<Box<T>>`. // SAFETY: This pointer originates from a `Pin<Box<T>>`.
unsafe { Pin::new_unchecked(r) } unsafe { Pin::new_unchecked(r) }
} }
unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> Pin<&'a mut T> { unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> Pin<&'a mut T> {
let ptr = ptr.cast();
// SAFETY: The safety requirements for this function ensure that the object is still alive, // SAFETY: The safety requirements for this function ensure that the object is still alive,
// so it is safe to dereference the raw pointer. // so it is safe to dereference the raw pointer.
// The safety requirements of `from_foreign` also ensure that the object remains alive for // The safety requirements of `from_foreign` also ensure that the object remains alive for

View File

@ -217,7 +217,7 @@ impl<T: MiscDevice> MiscdeviceVTable<T> {
// type. // type.
// //
// SAFETY: The open call of a file can access the private data. // SAFETY: The open call of a file can access the private data.
unsafe { (*raw_file).private_data = ptr.into_foreign().cast() }; unsafe { (*raw_file).private_data = ptr.into_foreign() };
0 0
} }
@ -228,7 +228,7 @@ impl<T: MiscDevice> MiscdeviceVTable<T> {
/// must be associated with a `MiscDeviceRegistration<T>`. /// must be associated with a `MiscDeviceRegistration<T>`.
unsafe extern "C" fn release(_inode: *mut bindings::inode, file: *mut bindings::file) -> c_int { unsafe extern "C" fn release(_inode: *mut bindings::inode, file: *mut bindings::file) -> c_int {
// SAFETY: The release call of a file owns the private data. // SAFETY: The release call of a file owns the private data.
let private = unsafe { (*file).private_data }.cast(); let private = unsafe { (*file).private_data };
// SAFETY: The release call of a file owns the private data. // SAFETY: The release call of a file owns the private data.
let ptr = unsafe { <T::Ptr as ForeignOwnable>::from_foreign(private) }; let ptr = unsafe { <T::Ptr as ForeignOwnable>::from_foreign(private) };
@ -272,7 +272,7 @@ impl<T: MiscDevice> MiscdeviceVTable<T> {
/// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`. /// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.
unsafe extern "C" fn ioctl(file: *mut bindings::file, cmd: c_uint, arg: c_ulong) -> c_long { unsafe extern "C" fn ioctl(file: *mut bindings::file, cmd: c_uint, arg: c_ulong) -> c_long {
// SAFETY: The ioctl call of a file can access the private data. // SAFETY: The ioctl call of a file can access the private data.
let private = unsafe { (*file).private_data }.cast(); let private = unsafe { (*file).private_data };
// SAFETY: Ioctl calls can borrow the private data of the file. // SAFETY: Ioctl calls can borrow the private data of the file.
let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
@ -297,7 +297,7 @@ impl<T: MiscDevice> MiscdeviceVTable<T> {
arg: c_ulong, arg: c_ulong,
) -> c_long { ) -> c_long {
// SAFETY: The compat ioctl call of a file can access the private data. // SAFETY: The compat ioctl call of a file can access the private data.
let private = unsafe { (*file).private_data }.cast(); let private = unsafe { (*file).private_data };
// SAFETY: Ioctl calls can borrow the private data of the file. // SAFETY: Ioctl calls can borrow the private data of the file.
let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
@ -318,7 +318,7 @@ impl<T: MiscDevice> MiscdeviceVTable<T> {
/// - `seq_file` must be a valid `struct seq_file` that we can write to. /// - `seq_file` must be a valid `struct seq_file` that we can write to.
unsafe extern "C" fn show_fdinfo(seq_file: *mut bindings::seq_file, file: *mut bindings::file) { unsafe extern "C" fn show_fdinfo(seq_file: *mut bindings::seq_file, file: *mut bindings::file) {
// SAFETY: The release call of a file owns the private data. // SAFETY: The release call of a file owns the private data.
let private = unsafe { (*file).private_data }.cast(); let private = unsafe { (*file).private_data };
// SAFETY: Ioctl calls can borrow the private data of the file. // SAFETY: Ioctl calls can borrow the private data of the file.
let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) }; let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
// SAFETY: // SAFETY:

View File

@ -89,7 +89,7 @@ extern "C" fn probe_callback(
extern "C" fn remove_callback(pdev: *mut bindings::pci_dev) { extern "C" fn remove_callback(pdev: *mut bindings::pci_dev) {
// SAFETY: The PCI bus only ever calls the remove callback with a valid pointer to a // SAFETY: The PCI bus only ever calls the remove callback with a valid pointer to a
// `struct pci_dev`. // `struct pci_dev`.
let ptr = unsafe { bindings::pci_get_drvdata(pdev) }.cast(); let ptr = unsafe { bindings::pci_get_drvdata(pdev) };
// SAFETY: `remove_callback` is only ever called after a successful call to // SAFETY: `remove_callback` is only ever called after a successful call to
// `probe_callback`, hence it's guaranteed that `ptr` points to a valid and initialized // `probe_callback`, hence it's guaranteed that `ptr` points to a valid and initialized

View File

@ -81,7 +81,7 @@ extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> kernel::ff
extern "C" fn remove_callback(pdev: *mut bindings::platform_device) { extern "C" fn remove_callback(pdev: *mut bindings::platform_device) {
// SAFETY: `pdev` is a valid pointer to a `struct platform_device`. // SAFETY: `pdev` is a valid pointer to a `struct platform_device`.
let ptr = unsafe { bindings::platform_get_drvdata(pdev) }.cast(); let ptr = unsafe { bindings::platform_get_drvdata(pdev) };
// SAFETY: `remove_callback` is only ever called after a successful call to // SAFETY: `remove_callback` is only ever called after a successful call to
// `probe_callback`, hence it's guaranteed that `ptr` points to a valid and initialized // `probe_callback`, hence it's guaranteed that `ptr` points to a valid and initialized

View File

@ -19,6 +19,7 @@
use crate::{ use crate::{
alloc::{AllocError, Flags, KBox}, alloc::{AllocError, Flags, KBox},
bindings, bindings,
ffi::c_void,
init::InPlaceInit, init::InPlaceInit,
try_init, try_init,
types::{ForeignOwnable, Opaque}, types::{ForeignOwnable, Opaque},
@ -141,10 +142,9 @@ pub struct Arc<T: ?Sized> {
_p: PhantomData<ArcInner<T>>, _p: PhantomData<ArcInner<T>>,
} }
#[doc(hidden)]
#[pin_data] #[pin_data]
#[repr(C)] #[repr(C)]
pub struct ArcInner<T: ?Sized> { struct ArcInner<T: ?Sized> {
refcount: Opaque<bindings::refcount_t>, refcount: Opaque<bindings::refcount_t>,
data: T, data: T,
} }
@ -373,20 +373,22 @@ pub fn into_unique_or_drop(self) -> Option<Pin<UniqueArc<T>>> {
} }
} }
// SAFETY: The `into_foreign` function returns a pointer that is well-aligned. // SAFETY: The pointer returned by `into_foreign` comes from a well aligned
// pointer to `ArcInner<T>`.
unsafe impl<T: 'static> ForeignOwnable for Arc<T> { unsafe impl<T: 'static> ForeignOwnable for Arc<T> {
type PointedTo = ArcInner<T>; const FOREIGN_ALIGN: usize = core::mem::align_of::<ArcInner<T>>();
type Borrowed<'a> = ArcBorrow<'a, T>; type Borrowed<'a> = ArcBorrow<'a, T>;
type BorrowedMut<'a> = Self::Borrowed<'a>; type BorrowedMut<'a> = Self::Borrowed<'a>;
fn into_foreign(self) -> *mut Self::PointedTo { fn into_foreign(self) -> *mut c_void {
ManuallyDrop::new(self).ptr.as_ptr() ManuallyDrop::new(self).ptr.as_ptr().cast()
} }
unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self { unsafe fn from_foreign(ptr: *mut c_void) -> Self {
// SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
// call to `Self::into_foreign`. // call to `Self::into_foreign`.
let inner = unsafe { NonNull::new_unchecked(ptr) }; let inner = unsafe { NonNull::new_unchecked(ptr.cast::<ArcInner<T>>()) };
// SAFETY: By the safety requirement of this function, we know that `ptr` came from // SAFETY: By the safety requirement of this function, we know that `ptr` came from
// a previous call to `Arc::into_foreign`, which guarantees that `ptr` is valid and // a previous call to `Arc::into_foreign`, which guarantees that `ptr` is valid and
@ -394,17 +396,17 @@ unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self {
unsafe { Self::from_inner(inner) } unsafe { Self::from_inner(inner) }
} }
unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> ArcBorrow<'a, T> { unsafe fn borrow<'a>(ptr: *mut c_void) -> ArcBorrow<'a, T> {
// SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
// call to `Self::into_foreign`. // call to `Self::into_foreign`.
let inner = unsafe { NonNull::new_unchecked(ptr) }; let inner = unsafe { NonNull::new_unchecked(ptr.cast::<ArcInner<T>>()) };
// SAFETY: The safety requirements of `from_foreign` ensure that the object remains alive // SAFETY: The safety requirements of `from_foreign` ensure that the object remains alive
// for the lifetime of the returned value. // for the lifetime of the returned value.
unsafe { ArcBorrow::new(inner) } unsafe { ArcBorrow::new(inner) }
} }
unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> ArcBorrow<'a, T> { unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> ArcBorrow<'a, T> {
// SAFETY: The safety requirements for `borrow_mut` are a superset of the safety // SAFETY: The safety requirements for `borrow_mut` are a superset of the safety
// requirements for `borrow`. // requirements for `borrow`.
unsafe { <Self as ForeignOwnable>::borrow(ptr) } unsafe { <Self as ForeignOwnable>::borrow(ptr) }

View File

@ -2,6 +2,7 @@
//! Kernel types. //! Kernel types.
use crate::ffi::c_void;
use core::{ use core::{
cell::UnsafeCell, cell::UnsafeCell,
marker::{PhantomData, PhantomPinned}, marker::{PhantomData, PhantomPinned},
@ -21,15 +22,10 @@
/// ///
/// # Safety /// # Safety
/// ///
/// Implementers must ensure that [`into_foreign`] returns a pointer which meets the alignment /// - Implementations must satisfy the guarantees of [`Self::into_foreign`].
/// requirements of [`PointedTo`].
///
/// [`into_foreign`]: Self::into_foreign
/// [`PointedTo`]: Self::PointedTo
pub unsafe trait ForeignOwnable: Sized { pub unsafe trait ForeignOwnable: Sized {
/// Type used when the value is foreign-owned. In practical terms only defines the alignment of /// The alignment of pointers returned by `into_foreign`.
/// the pointer. const FOREIGN_ALIGN: usize;
type PointedTo;
/// Type used to immutably borrow a value that is currently foreign-owned. /// Type used to immutably borrow a value that is currently foreign-owned.
type Borrowed<'a>; type Borrowed<'a>;
@ -39,18 +35,20 @@ pub unsafe trait ForeignOwnable: Sized {
/// Converts a Rust-owned object to a foreign-owned one. /// Converts a Rust-owned object to a foreign-owned one.
/// ///
/// The foreign representation is a pointer to void. Aside from the guarantees listed below,
/// there are no other guarantees for this pointer. For example, it might be invalid, dangling
/// or pointing to uninitialized memory. Using it in any way except for [`from_foreign`],
/// [`try_from_foreign`], [`borrow`], or [`borrow_mut`] can result in undefined behavior.
///
/// # Guarantees /// # Guarantees
/// ///
/// The return value is guaranteed to be well-aligned, but there are no other guarantees for /// - Minimum alignment of returned pointer is [`Self::FOREIGN_ALIGN`].
/// this pointer. For example, it might be null, dangling, or point to uninitialized memory.
/// Using it in any way except for [`ForeignOwnable::from_foreign`], [`ForeignOwnable::borrow`],
/// [`ForeignOwnable::try_from_foreign`] can result in undefined behavior.
/// ///
/// [`from_foreign`]: Self::from_foreign /// [`from_foreign`]: Self::from_foreign
/// [`try_from_foreign`]: Self::try_from_foreign /// [`try_from_foreign`]: Self::try_from_foreign
/// [`borrow`]: Self::borrow /// [`borrow`]: Self::borrow
/// [`borrow_mut`]: Self::borrow_mut /// [`borrow_mut`]: Self::borrow_mut
fn into_foreign(self) -> *mut Self::PointedTo; fn into_foreign(self) -> *mut c_void;
/// Converts a foreign-owned object back to a Rust-owned one. /// Converts a foreign-owned object back to a Rust-owned one.
/// ///
@ -60,7 +58,7 @@ pub unsafe trait ForeignOwnable: Sized {
/// must not be passed to `from_foreign` more than once. /// must not be passed to `from_foreign` more than once.
/// ///
/// [`into_foreign`]: Self::into_foreign /// [`into_foreign`]: Self::into_foreign
unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self; unsafe fn from_foreign(ptr: *mut c_void) -> Self;
/// Tries to convert a foreign-owned object back to a Rust-owned one. /// Tries to convert a foreign-owned object back to a Rust-owned one.
/// ///
@ -72,7 +70,7 @@ pub unsafe trait ForeignOwnable: Sized {
/// `ptr` must either be null or satisfy the safety requirements for [`from_foreign`]. /// `ptr` must either be null or satisfy the safety requirements for [`from_foreign`].
/// ///
/// [`from_foreign`]: Self::from_foreign /// [`from_foreign`]: Self::from_foreign
unsafe fn try_from_foreign(ptr: *mut Self::PointedTo) -> Option<Self> { unsafe fn try_from_foreign(ptr: *mut c_void) -> Option<Self> {
if ptr.is_null() { if ptr.is_null() {
None None
} else { } else {
@ -95,7 +93,7 @@ unsafe fn try_from_foreign(ptr: *mut Self::PointedTo) -> Option<Self> {
/// ///
/// [`into_foreign`]: Self::into_foreign /// [`into_foreign`]: Self::into_foreign
/// [`from_foreign`]: Self::from_foreign /// [`from_foreign`]: Self::from_foreign
unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> Self::Borrowed<'a>; unsafe fn borrow<'a>(ptr: *mut c_void) -> Self::Borrowed<'a>;
/// Borrows a foreign-owned object mutably. /// Borrows a foreign-owned object mutably.
/// ///
@ -123,23 +121,24 @@ unsafe fn try_from_foreign(ptr: *mut Self::PointedTo) -> Option<Self> {
/// [`from_foreign`]: Self::from_foreign /// [`from_foreign`]: Self::from_foreign
/// [`borrow`]: Self::borrow /// [`borrow`]: Self::borrow
/// [`Arc`]: crate::sync::Arc /// [`Arc`]: crate::sync::Arc
unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> Self::BorrowedMut<'a>; unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> Self::BorrowedMut<'a>;
} }
// SAFETY: The `into_foreign` function returns a pointer that is dangling, but well-aligned. // SAFETY: The pointer returned by `into_foreign` comes from a well aligned
// pointer to `()`.
unsafe impl ForeignOwnable for () { unsafe impl ForeignOwnable for () {
type PointedTo = (); const FOREIGN_ALIGN: usize = core::mem::align_of::<()>();
type Borrowed<'a> = (); type Borrowed<'a> = ();
type BorrowedMut<'a> = (); type BorrowedMut<'a> = ();
fn into_foreign(self) -> *mut Self::PointedTo { fn into_foreign(self) -> *mut c_void {
core::ptr::NonNull::dangling().as_ptr() core::ptr::NonNull::dangling().as_ptr()
} }
unsafe fn from_foreign(_: *mut Self::PointedTo) -> Self {} unsafe fn from_foreign(_: *mut c_void) -> Self {}
unsafe fn borrow<'a>(_: *mut Self::PointedTo) -> Self::Borrowed<'a> {} unsafe fn borrow<'a>(_: *mut c_void) -> Self::Borrowed<'a> {}
unsafe fn borrow_mut<'a>(_: *mut Self::PointedTo) -> Self::BorrowedMut<'a> {} unsafe fn borrow_mut<'a>(_: *mut c_void) -> Self::BorrowedMut<'a> {}
} }
/// Runs a cleanup function/closure when dropped. /// Runs a cleanup function/closure when dropped.

View File

@ -7,9 +7,10 @@
use crate::{ use crate::{
alloc, bindings, build_assert, alloc, bindings, build_assert,
error::{Error, Result}, error::{Error, Result},
ffi::c_void,
types::{ForeignOwnable, NotThreadSafe, Opaque}, types::{ForeignOwnable, NotThreadSafe, Opaque},
}; };
use core::{iter, marker::PhantomData, mem, pin::Pin, ptr::NonNull}; use core::{iter, marker::PhantomData, pin::Pin, ptr::NonNull};
use pin_init::{pin_data, pin_init, pinned_drop, PinInit}; use pin_init::{pin_data, pin_init, pinned_drop, PinInit};
/// An array which efficiently maps sparse integer indices to owned objects. /// An array which efficiently maps sparse integer indices to owned objects.
@ -101,7 +102,7 @@ pub fn new(kind: AllocKind) -> impl PinInit<Self> {
}) })
} }
fn iter(&self) -> impl Iterator<Item = NonNull<T::PointedTo>> + '_ { fn iter(&self) -> impl Iterator<Item = NonNull<c_void>> + '_ {
let mut index = 0; let mut index = 0;
// SAFETY: `self.xa` is always valid by the type invariant. // SAFETY: `self.xa` is always valid by the type invariant.
@ -179,7 +180,7 @@ fn from(value: StoreError<T>) -> Self {
impl<'a, T: ForeignOwnable> Guard<'a, T> { impl<'a, T: ForeignOwnable> Guard<'a, T> {
fn load<F, U>(&self, index: usize, f: F) -> Option<U> fn load<F, U>(&self, index: usize, f: F) -> Option<U>
where where
F: FnOnce(NonNull<T::PointedTo>) -> U, F: FnOnce(NonNull<c_void>) -> U,
{ {
// SAFETY: `self.xa.xa` is always valid by the type invariant. // SAFETY: `self.xa.xa` is always valid by the type invariant.
let ptr = unsafe { bindings::xa_load(self.xa.xa.get(), index) }; let ptr = unsafe { bindings::xa_load(self.xa.xa.get(), index) };
@ -230,7 +231,7 @@ pub fn store(
gfp: alloc::Flags, gfp: alloc::Flags,
) -> Result<Option<T>, StoreError<T>> { ) -> Result<Option<T>, StoreError<T>> {
build_assert!( build_assert!(
mem::align_of::<T::PointedTo>() >= 4, T::FOREIGN_ALIGN >= 4,
"pointers stored in XArray must be 4-byte aligned" "pointers stored in XArray must be 4-byte aligned"
); );
let new = value.into_foreign(); let new = value.into_foreign();