* [PATCH] rust: kernel: update `container_of` to not require unsafe blocks
@ 2025-01-30 10:11 Florian Rädiker
2025-01-30 10:15 ` Alice Ryhl
0 siblings, 1 reply; 3+ messages in thread
From: Florian Rädiker @ 2025-01-30 10:11 UTC (permalink / raw)
To: Miguel Ojeda, Alex Gaynor
Cc: Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Alice Ryhl, Trevor Gross, rust-for-linux,
Clemens Tiedt, Florian Rädiker
The calculation done by `container_of` does not have to be unsafe, so
change this.
Inspired by [0] by Wedson Almeida Filho <walmeida@microsoft.com>
[0] https://github.com/Rust-for-Linux/linux/commit/ecc54b2bbd08f62f8cd16420d3d6c60b517a05cd
Signed-off-by: Florian Rädiker <git@flra.eu>
---
Hi,
this is my first-ever patch submission :)
I thought this might serve as a "good first issue".
Best,
flra
rust/kernel/lib.rs | 13 ++++++------
rust/kernel/rbtree.rs | 46 +++++++++++++++++++++----------------------
2 files changed, 30 insertions(+), 29 deletions(-)
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 545d1170ee63..343d8b9ea32e 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -153,8 +153,8 @@ fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
///
/// # Safety
///
-/// The pointer passed to this macro, and the pointer returned by this macro, must both be in
-/// bounds of the same allocation.
+/// This operation itself is always safe, but using the result is only safe if the resulting
+/// pointer, and the pointer passed to this macro, are in bounds of the same allocation.
///
/// # Examples
///
@@ -167,9 +167,9 @@ fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
///
/// let test = Test { a: 10, b: 20 };
/// let b_ptr = &test.b;
-/// // SAFETY: The pointer points at the `b` field of a `Test`, so the resulting pointer will be
-/// // in-bounds of the same allocation as `b_ptr`.
-/// let test_alias = unsafe { container_of!(b_ptr, Test, b) };
+/// // The pointer points at the `b` field of a `Test`, so the resulting pointer will be in-bounds
+/// // of the same allocation as `b_ptr`.
+/// let test_alias = container_of!(b_ptr, Test, b);
/// assert!(core::ptr::eq(&test, test_alias));
/// ```
#[macro_export]
@@ -177,7 +177,8 @@ macro_rules! container_of {
($ptr:expr, $type:ty, $($f:tt)*) => {{
let ptr = $ptr as *const _ as *const u8;
let offset: usize = ::core::mem::offset_of!($type, $($f)*);
- ptr.sub(offset) as *const $type
+ $crate::build_assert!(offset <= isize::MAX as usize);
+ ptr.wrapping_sub(offset) as *const $type
}}
}
diff --git a/rust/kernel/rbtree.rs b/rust/kernel/rbtree.rs
index ee2731dad72d..f61d7f80c2ca 100644
--- a/rust/kernel/rbtree.rs
+++ b/rust/kernel/rbtree.rs
@@ -328,8 +328,8 @@ fn raw_entry(&mut self, key: &K) -> RawEntry<'_, K, V> {
unsafe { &mut (*raw_self).root.rb_node };
while !(*child_field_of_parent).is_null() {
let curr = *child_field_of_parent;
- // SAFETY: All links fields we create are in a `Node<K, V>`.
- let node = unsafe { container_of!(curr, Node<K, V>, links) };
+ // All links fields we create are in a `Node<K, V>`, so `node` is safe to dereference.
+ let node = container_of!(curr, Node<K, V>, links);
// SAFETY: `node` is a non-null node so it is valid by the type invariants.
match key.cmp(unsafe { &(*node).key }) {
@@ -375,9 +375,9 @@ pub fn find_mut(&mut self, key: &K) -> Option<OccupiedEntry<'_, K, V>> {
pub fn get(&self, key: &K) -> Option<&V> {
let mut node = self.root.rb_node;
while !node.is_null() {
- // SAFETY: By the type invariant of `Self`, all non-null `rb_node` pointers stored in `self`
- // point to the links field of `Node<K, V>` objects.
- let this = unsafe { container_of!(node, Node<K, V>, links) };
+ // By the type invariant of `Self`, all non-null `rb_node` pointers stored in `self`
+ // point to the links field of `Node<K, V>` objects, so `this` is safe to dereference.
+ let this = container_of!(node, Node<K, V>, links);
// SAFETY: `this` is a non-null node so it is valid by the type invariants.
node = match key.cmp(unsafe { &(*this).key }) {
// SAFETY: `node` is a non-null node so it is valid by the type invariants.
@@ -422,9 +422,9 @@ pub fn cursor_lower_bound(&mut self, key: &K) -> Option<Cursor<'_, K, V>>
let mut node = self.root.rb_node;
let mut best_match: Option<NonNull<Node<K, V>>> = None;
while !node.is_null() {
- // SAFETY: By the type invariant of `Self`, all non-null `rb_node` pointers stored in `self`
- // point to the links field of `Node<K, V>` objects.
- let this = unsafe { container_of!(node, Node<K, V>, links) }.cast_mut();
+ // By the type invariant of `Self`, all non-null `rb_node` pointers stored in `self`
+ // point to the links field of `Node<K, V>` objects, so `this` is safe to dereference.
+ let this = container_of!(node, Node<K, V>, links).cast_mut();
// SAFETY: `this` is a non-null node so it is valid by the type invariants.
let this_key = unsafe { &(*this).key };
// SAFETY: `node` is a non-null node so it is valid by the type invariants.
@@ -485,8 +485,8 @@ fn drop(&mut self) {
// INVARIANT: The loop invariant is that all tree nodes from `next` in postorder are valid.
while !next.is_null() {
- // SAFETY: All links fields we create are in a `Node<K, V>`.
- let this = unsafe { container_of!(next, Node<K, V>, links) };
+ // All links fields we create are in a `Node<K, V>`, so `this` is safe to use.
+ let this = container_of!(next, Node<K, V>, links);
// Find out what the next node is before disposing of the current one.
// SAFETY: `next` and all nodes in postorder are still valid.
@@ -759,9 +759,9 @@ pub fn current_mut(&mut self) -> (&K, &mut V) {
pub fn remove_current(self) -> (Option<Self>, RBTreeNode<K, V>) {
let prev = self.get_neighbor_raw(Direction::Prev);
let next = self.get_neighbor_raw(Direction::Next);
- // SAFETY: By the type invariant of `Self`, all non-null `rb_node` pointers stored in `self`
- // point to the links field of `Node<K, V>` objects.
- let this = unsafe { container_of!(self.current.as_ptr(), Node<K, V>, links) }.cast_mut();
+ // By the type invariant of `Self`, all non-null `rb_node` pointers stored in `self`
+ // point to the links field of `Node<K, V>` objects, so `this` is safe to dereference.
+ let this = container_of!(self.current.as_ptr(), Node<K, V>, links).cast_mut();
// SAFETY: `this` is valid by the type invariants as described above.
let node = unsafe { KBox::from_raw(this) };
let node = RBTreeNode { node };
@@ -804,9 +804,9 @@ fn remove_neighbor(&mut self, direction: Direction) -> Option<RBTreeNode<K, V>>
// SAFETY: The reference to the tree used to create the cursor outlives the cursor, so
// the tree cannot change. By the tree invariant, all nodes are valid.
unsafe { bindings::rb_erase(neighbor, addr_of_mut!(self.tree.root)) };
- // SAFETY: By the type invariant of `Self`, all non-null `rb_node` pointers stored in `self`
- // point to the links field of `Node<K, V>` objects.
- let this = unsafe { container_of!(neighbor, Node<K, V>, links) }.cast_mut();
+ // By the type invariant of `Self`, all non-null `rb_node` pointers stored in `self`
+ // point to the links field of `Node<K, V>` objects, so `this` is safe to dereference.
+ let this = container_of!(neighbor, Node<K, V>, links).cast_mut();
// SAFETY: `this` is valid by the type invariants as described above.
let node = unsafe { KBox::from_raw(this) };
return Some(RBTreeNode { node });
@@ -910,9 +910,9 @@ unsafe fn to_key_value_mut<'b>(node: NonNull<bindings::rb_node>) -> (&'b K, &'b
/// - `node` must be a valid pointer to a node in an [`RBTree`].
/// - The caller has immutable access to the key for the duration of 'b.
unsafe fn to_key_value_raw<'b>(node: NonNull<bindings::rb_node>) -> (&'b K, *mut V) {
- // SAFETY: By the type invariant of `Self`, all non-null `rb_node` pointers stored in `self`
- // point to the links field of `Node<K, V>` objects.
- let this = unsafe { container_of!(node.as_ptr(), Node<K, V>, links) }.cast_mut();
+ // By the type invariant of `Self`, all non-null `rb_node` pointers stored in `self`
+ // point to the links field of `Node<K, V>` objects, so `this` is safe to dereference.
+ let this = container_of!(node.as_ptr(), Node<K, V>, links).cast_mut();
// SAFETY: The passed `node` is the current node or a non-null neighbor,
// thus `this` is valid by the type invariants.
let k = unsafe { &(*this).key };
@@ -1019,14 +1019,14 @@ fn next(&mut self) -> Option<Self::Item> {
return None;
}
- // SAFETY: By the type invariant of `IterRaw`, `self.next` is a valid node in an `RBTree`,
- // and by the type invariant of `RBTree`, all nodes point to the links field of `Node<K, V>` objects.
- let cur = unsafe { container_of!(self.next, Node<K, V>, links) }.cast_mut();
+ // By the type invariant of `IterRaw`, `self.next` is a valid node in an `RBTree`, and by the
+ // type invariant of `RBTree`, all nodes point to the links field of `Node<K, V>` objects.
+ let cur = container_of!(self.next, Node<K, V>, links).cast_mut();
// SAFETY: `self.next` is a valid tree node by the type invariants.
self.next = unsafe { bindings::rb_next(self.next) };
- // SAFETY: By the same reasoning above, it is safe to dereference the node.
+ // SAFETY: By the reasoning above, it is safe to dereference `cur`.
Some(unsafe { (addr_of_mut!((*cur).key), addr_of_mut!((*cur).value)) })
}
}
base-commit: ceff0757f5dafb5be5205988171809c877b1d3e3
--
2.47.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] rust: kernel: update `container_of` to not require unsafe blocks
2025-01-30 10:11 [PATCH] rust: kernel: update `container_of` to not require unsafe blocks Florian Rädiker
@ 2025-01-30 10:15 ` Alice Ryhl
2025-01-30 10:22 ` Raediker, Florian
0 siblings, 1 reply; 3+ messages in thread
From: Alice Ryhl @ 2025-01-30 10:15 UTC (permalink / raw)
To: Florian Rädiker
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Trevor Gross, rust-for-linux, Clemens Tiedt
On Thu, Jan 30, 2025 at 11:12 AM Florian Rädiker <git@flra.eu> wrote:
>
> The calculation done by `container_of` does not have to be unsafe, so
> change this.
>
> Inspired by [0] by Wedson Almeida Filho <walmeida@microsoft.com>
>
> [0] https://github.com/Rust-for-Linux/linux/commit/ecc54b2bbd08f62f8cd16420d3d6c60b517a05cd
>
> Signed-off-by: Florian Rädiker <git@flra.eu>
When we added container_of! to the kernel, I argued that it should be
unsafe. It has the advantage of using pointer::sub instead of
wrapping_sub, which gives more information to the compiler that it is
better able to optimize. The unsafe is rarely a problem in practice,
since you're always going to immediately dereference the pointer after
performing the container_of operation, so you need what it requires to
be true either way.
> Hi,
>
> this is my first-ever patch submission :)
> I thought this might serve as a "good first issue".
Was this listed as a good first issue on the issue tracker? I hope not ...
Alice
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] rust: kernel: update `container_of` to not require unsafe blocks
2025-01-30 10:15 ` Alice Ryhl
@ 2025-01-30 10:22 ` Raediker, Florian
0 siblings, 0 replies; 3+ messages in thread
From: Raediker, Florian @ 2025-01-30 10:22 UTC (permalink / raw)
To: git@flra.eu, aliceryhl@google.com
Cc: tmgross@umich.edu, benno.lossin@proton.me, Tiedt, Clemens,
gary@garyguo.net, a.hindborg@kernel.org,
rust-for-linux@vger.kernel.org, bjorn3_gh@protonmail.com,
boqun.feng@gmail.com, alex.gaynor@gmail.com, ojeda@kernel.org
On Thu, 2025-01-30 at 11:15 +0100, Alice Ryhl wrote:
> When we added container_of! to the kernel, I argued that it should be
> unsafe. It has the advantage of using pointer::sub instead of
> wrapping_sub, which gives more information to the compiler that it is
> better able to optimize. The unsafe is rarely a problem in practice,
> since you're always going to immediately dereference the pointer after
> performing the container_of operation, so you need what it requires to
> be true either way.
Thanks for the explanation!
> > Hi,
> >
> > this is my first-ever patch submission :)
> > I thought this might serve as a "good first issue".
>
> Was this listed as a good first issue on the issue tracker? I hope not ...
No, I was simply working with Wedson's VFS abstractions and thought this smaller
commit might be a good first submission.
Best,
flra
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2025-01-30 10:29 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-01-30 10:11 [PATCH] rust: kernel: update `container_of` to not require unsafe blocks Florian Rädiker
2025-01-30 10:15 ` Alice Ryhl
2025-01-30 10:22 ` Raediker, Florian
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).