Skip to content

Commit 4c5962d

Browse files
Darksonnfbq
authored andcommitted
rust: add improved version of ForeignOwnable::borrow_mut
Previously, the `ForeignOwnable` trait had a method called `borrow_mut` that was intended to provide mutable access to the inner value. However, the method accidentally made it possible to change the address of the object being modified, which usually isn't what we want. (And when we want that, it can be done by calling `from_foreign` and `into_foreign`, like how the old `borrow_mut` was implemented.) In this patch, we introduce an alternate definition of `borrow_mut` that solves the previous problem. Conceptually, given a pointer type `P` that implements `ForeignOwnable`, the `borrow_mut` method gives you the same kind of access as an `&mut P` would, except that it does not let you change the pointer `P` itself. This is analogous to how the existing `borrow` method provides the same kind of access to the inner value as an `&P`. Note that for types like `Arc`, having an `&mut Arc<T>` only gives you immutable access to the inner `T`. This is because mutable references assume exclusive access, but there might be other handles to the same reference counted value, so the access isn't exclusive. The `Arc` type implements this by making `borrow_mut` return the same type as `borrow`. Signed-off-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Benno Lossin <benno.lossin@proton.me> Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com> Reviewed-by: Boqun Feng <boqun.feng@gmail.com> Link: https://lore.kernel.org/r/20230710074642.683831-1-aliceryhl@google.com [boqun: resolve conflicts with `try_from_foreign`]
1 parent 1613e60 commit 4c5962d

File tree

2 files changed

+86
-32
lines changed

2 files changed

+86
-32
lines changed

rust/kernel/sync/arc.rs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -356,26 +356,35 @@ impl<T: ?Sized> Arc<T> {
356356

357357
impl<T: 'static> ForeignOwnable for Arc<T> {
358358
type Borrowed<'a> = ArcBorrow<'a, T>;
359+
// Mutable access to the `Arc` does not give any extra abilities over
360+
// immutable access.
361+
type BorrowedMut<'a> = ArcBorrow<'a, T>;
359362

360363
fn into_foreign(self) -> *const core::ffi::c_void {
361364
ManuallyDrop::new(self).ptr.as_ptr() as _
362365
}
363366

367+
unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self {
368+
// SAFETY: By the safety requirement of this function, we know that `ptr` came from
369+
// a previous call to `Arc::into_foreign`, which guarantees that `ptr` is valid and
370+
// holds a reference count increment that is transferrable to us.
371+
unsafe { Self::from_inner(NonNull::new_unchecked(ptr as _)) }
372+
}
373+
364374
unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> ArcBorrow<'a, T> {
365375
// SAFETY: By the safety requirement of this function, we know that `ptr` came from
366376
// a previous call to `Arc::into_foreign`.
367-
let inner = NonNull::new(ptr as *mut ArcInner<T>).unwrap();
377+
let inner = unsafe { NonNull::new_unchecked(ptr as *mut ArcInner<T>) };
368378

369-
// SAFETY: The safety requirements of `from_foreign` ensure that the object remains alive
370-
// for the lifetime of the returned value.
379+
// SAFETY: The safety requirements ensure that we will not give up our
380+
// foreign-owned refcount while the `ArcBorrow` is still live.
371381
unsafe { ArcBorrow::new(inner) }
372382
}
373383

374-
unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self {
375-
// SAFETY: By the safety requirement of this function, we know that `ptr` came from
376-
// a previous call to `Arc::into_foreign`, which guarantees that `ptr` is valid and
377-
// holds a reference count increment that is transferrable to us.
378-
unsafe { Self::from_inner(NonNull::new(ptr as _).unwrap()) }
384+
unsafe fn borrow_mut<'a>(ptr: *const core::ffi::c_void) -> ArcBorrow<'a, T> {
385+
// SAFETY: The safety requirements for `borrow_mut` are a superset of the safety
386+
// requirements for `borrow`.
387+
unsafe { Self::borrow(ptr) }
379388
}
380389
}
381390

rust/kernel/types.rs

Lines changed: 69 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,31 +20,25 @@ use core::{
2020
/// This trait is meant to be used in cases when Rust objects are stored in C objects and
2121
/// eventually "freed" back to Rust.
2222
pub trait ForeignOwnable: Sized {
23-
/// Type of values borrowed between calls to [`ForeignOwnable::into_foreign`] and
24-
/// [`ForeignOwnable::from_foreign`].
23+
/// Type used to immutably borrow a value that is currently foreign-owned.
2524
type Borrowed<'a>;
2625

26+
/// Type used to mutably borrow a value that is currently foreign-owned.
27+
type BorrowedMut<'a>;
28+
2729
/// Converts a Rust-owned object to a foreign-owned one.
2830
///
2931
/// The foreign representation is a pointer to void.
3032
fn into_foreign(self) -> *const core::ffi::c_void;
3133

32-
/// Borrows a foreign-owned object.
33-
///
34-
/// # Safety
35-
///
36-
/// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for
37-
/// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet.
38-
unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Self::Borrowed<'a>;
39-
4034
/// Converts a foreign-owned object back to a Rust-owned one.
4135
///
4236
/// # Safety
4337
///
44-
/// `ptr` must have been returned by a previous call to [`ForeignOwnable::into_foreign`] for
45-
/// which a previous matching [`ForeignOwnable::from_foreign`] hasn't been called yet.
46-
/// Additionally, all instances (if any) of values returned by [`ForeignOwnable::borrow`] for
47-
/// this object must have been dropped.
38+
/// The provided pointer must have been returned by a previous call to [`into_foreign`], and it
39+
/// must not be passed to `from_foreign` more than once.
40+
///
41+
/// [`into_foreign`]: Self::into_foreign
4842
unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self;
4943

5044
/// Tries to convert a foreign-owned object back to a Rust-owned one.
@@ -65,40 +59,91 @@ pub trait ForeignOwnable: Sized {
6559
unsafe { Some(Self::from_foreign(ptr)) }
6660
}
6761
}
62+
63+
/// Borrows a foreign-owned object immutably.
64+
///
65+
/// This method provides a way to access a foreign-owned value from Rust immutably. It provides
66+
/// you with exactly the same abilities as an `&Self` when the value is Rust-owned.
67+
///
68+
/// # Safety
69+
///
70+
/// The provided pointer must have been returned by a previous call to [`into_foreign`], and if
71+
/// the pointer is ever passed to [`from_foreign`], then that call must happen after the end of
72+
/// the lifetime 'a.
73+
///
74+
/// [`into_foreign`]: Self::into_foreign
75+
/// [`from_foreign`]: Self::from_foreign
76+
unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> Self::Borrowed<'a>;
77+
78+
/// Borrows a foreign-owned object mutably.
79+
///
80+
/// This method provides a way to access a foreign-owned value from Rust mutably. It provides
81+
/// you with exactly the same abilities as an `&mut Self` when the value is Rust-owned, except
82+
/// that this method does not let you swap the foreign-owned object for another. (That is, it
83+
/// does not let you change the address of the void pointer that the foreign code is storing.)
84+
///
85+
/// Note that for types like [`Arc`], an `&mut Arc<T>` only gives you immutable access to the
86+
/// inner value, so this method also only provides immutable access in that case.
87+
///
88+
/// In the case of `Box<T>`, this method gives you the ability to modify the inner `T`, but it
89+
/// does not let you change the box itself. That is, you cannot change which allocation the box
90+
/// points at.
91+
///
92+
/// # Safety
93+
///
94+
/// The provided pointer must have been returned by a previous call to [`into_foreign`], and if
95+
/// the pointer is ever passed to [`from_foreign`], then that call must happen after the end of
96+
/// the lifetime 'a.
97+
///
98+
/// The lifetime 'a must not overlap with the lifetime of any other call to [`borrow`] or
99+
/// `borrow_mut` on the same object.
100+
///
101+
/// [`into_foreign`]: Self::into_foreign
102+
/// [`from_foreign`]: Self::from_foreign
103+
/// [`borrow`]: Self::borrow
104+
/// [`Arc`]: crate::sync::Arc
105+
unsafe fn borrow_mut<'a>(ptr: *const core::ffi::c_void) -> Self::BorrowedMut<'a>;
68106
}
69107

70108
impl<T: 'static> ForeignOwnable for Box<T> {
71109
type Borrowed<'a> = &'a T;
110+
type BorrowedMut<'a> = &'a mut T;
72111

73112
fn into_foreign(self) -> *const core::ffi::c_void {
74113
Box::into_raw(self) as _
75114
}
76115

77-
unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> &'a T {
78-
// SAFETY: The safety requirements for this function ensure that the object is still alive,
79-
// so it is safe to dereference the raw pointer.
80-
// The safety requirements of `from_foreign` also ensure that the object remains alive for
81-
// the lifetime of the returned value.
82-
unsafe { &*ptr.cast() }
83-
}
84-
85116
unsafe fn from_foreign(ptr: *const core::ffi::c_void) -> Self {
86117
// SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
87118
// call to `Self::into_foreign`.
88119
unsafe { Box::from_raw(ptr as _) }
89120
}
121+
122+
unsafe fn borrow<'a>(ptr: *const core::ffi::c_void) -> &'a T {
123+
// SAFETY: The safety requirements of this method ensure that the object remains alive and
124+
// immutable for the duration of 'a.
125+
unsafe { &*ptr.cast() }
126+
}
127+
128+
unsafe fn borrow_mut<'a>(ptr: *const core::ffi::c_void) -> &'a mut T {
129+
// SAFETY: The safety requirements of this method ensure that the pointer is valid and that
130+
// nothing else will access the value for the duration of 'a.
131+
unsafe { &mut *ptr.cast_mut().cast() }
132+
}
90133
}
91134

92135
impl ForeignOwnable for () {
93136
type Borrowed<'a> = ();
137+
type BorrowedMut<'a> = ();
94138

95139
fn into_foreign(self) -> *const core::ffi::c_void {
96140
core::ptr::NonNull::dangling().as_ptr()
97141
}
98142

99-
unsafe fn borrow<'a>(_: *const core::ffi::c_void) -> Self::Borrowed<'a> {}
100-
101143
unsafe fn from_foreign(_: *const core::ffi::c_void) -> Self {}
144+
145+
unsafe fn borrow<'a>(_: *const core::ffi::c_void) -> Self::Borrowed<'a> {}
146+
unsafe fn borrow_mut<'a>(_: *const core::ffi::c_void) -> Self::BorrowedMut<'a> {}
102147
}
103148

104149
/// Runs a cleanup function/closure when dropped.

0 commit comments

Comments
 (0)