* [PATCH v4] rust: check type of `$ptr` in `container_of!`
@ 2025-05-29 13:11 Tamir Duberstein
2025-05-29 13:24 ` Miguel Ojeda
` (3 more replies)
0 siblings, 4 replies; 8+ messages in thread
From: Tamir Duberstein @ 2025-05-29 13:11 UTC (permalink / raw)
To: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Benno Lossin
Cc: rust-for-linux, linux-kernel, Tamir Duberstein
Add a compile-time check that `*$ptr` is of the type of `$type->$($f)*`.
Rename those placeholders for clarity.
Given the incorrect usage:
> diff --git a/rust/kernel/rbtree.rs b/rust/kernel/rbtree.rs
> index 8d978c896747..6a7089149878 100644
> --- a/rust/kernel/rbtree.rs
> +++ b/rust/kernel/rbtree.rs
> @@ -329,7 +329,7 @@ fn raw_entry(&mut self, key: &K) -> RawEntry<'_, K, V> {
> 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) };
> + let node = unsafe { container_of!(curr, Node<K, V>, key) };
>
> // SAFETY: `node` is a non-null node so it is valid by the type invariants.
> match key.cmp(unsafe { &(*node).key }) {
this patch produces the compilation error:
> error[E0308]: mismatched types
> --> rust/kernel/lib.rs:220:45
> |
> 220 | $crate::assert_same_type(field_ptr, (&raw const (*container_ptr).$($fields)*).cast_mut());
> | ------------------------ --------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `*mut rb_node`, found `*mut K`
> | | |
> | | expected all arguments to be this `*mut bindings::rb_node` type because they need to match the type of this parameter
> | arguments to this function are incorrect
> |
> ::: rust/kernel/rbtree.rs:270:6
> |
> 270 | impl<K, V> RBTree<K, V>
> | - found this type parameter
> ...
> 332 | let node = unsafe { container_of!(curr, Node<K, V>, key) };
> | ------------------------------------ in this macro invocation
> |
> = note: expected raw pointer `*mut bindings::rb_node`
> found raw pointer `*mut K`
> note: function defined here
> --> rust/kernel/lib.rs:227:8
> |
> 227 | pub fn assert_same_type<T>(_: T, _: T) {}
> | ^^^^^^^^^^^^^^^^ - ---- ---- this parameter needs to match the `*mut bindings::rb_node` type of parameter #1
> | | |
> | | parameter #2 needs to match the `*mut bindings::rb_node` type of this parameter
> | parameter #1 and parameter #2 both reference this parameter `T`
> = note: this error originates in the macro `container_of` (in Nightly builds, run with -Z macro-backtrace for more info)
Suggested-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/all/CAH5fLgh6gmqGBhPMi2SKn7mCmMWfOSiS0WP5wBuGPYh9ZTAiww@mail.gmail.com/
Signed-off-by: Tamir Duberstein <tamird@gmail.com>
---
Changes in v4:
- Revert back to v1 with assert_same_type extracted out of the macro. (Miguel Ojeda)
- Drop Benno's RB since the implementation changed.
- Rebase on rust-next.
- Link to v3: https://lore.kernel.org/r/20250423-b4-container-of-type-check-v3-1-7994c56cf359@gmail.com
Changes in v3:
- Fix comment typo.
- s/^;/ / in commit message and cover letter. (Miguel Ojeda)
- Evaluate $ptr only once. (Alice Ryhl)
- Link to v2: https://lore.kernel.org/r/20250412-b4-container-of-type-check-v2-1-f3cc9934c160@gmail.com
Changes in v2:
- Wrap in `if false` to improve unoptimized codegen. (Alice Ryhl)
- Shrink implementation using an array literal instead of a function.
- Link to v1: https://lore.kernel.org/r/20250411-b4-container-of-type-check-v1-1-08262ef67c95@gmail.com
---
rust/kernel/lib.rs | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 909d305d0be8..b69b345ab778 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -213,12 +213,19 @@ fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
/// ```
#[macro_export]
macro_rules! container_of {
- ($ptr:expr, $type:ty, $($f:tt)*) => {{
- let offset: usize = ::core::mem::offset_of!($type, $($f)*);
- $ptr.byte_sub(offset).cast::<$type>()
+ ($field_ptr:expr, $Container:ty, $($fields:tt)*) => {{
+ let offset: usize = ::core::mem::offset_of!($Container, $($fields)*);
+ let field_ptr = $field_ptr;
+ let container_ptr = field_ptr.byte_sub(offset).cast::<$Container>();
+ $crate::assert_same_type(field_ptr, (&raw const (*container_ptr).$($fields)*).cast_mut());
+ container_ptr
}}
}
+/// Helper for `container_of!`.
+#[doc(hidden)]
+pub fn assert_same_type<T>(_: T, _: T) {}
+
/// Helper for `.rs.S` files.
#[doc(hidden)]
#[macro_export]
---
base-commit: 1ce98bb2bb30713ec4374ef11ead0d7d3e856766
change-id: 20250411-b4-container-of-type-check-06af1c204f59
Best regards,
--
Tamir Duberstein <tamird@gmail.com>
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v4] rust: check type of `$ptr` in `container_of!`
2025-05-29 13:11 [PATCH v4] rust: check type of `$ptr` in `container_of!` Tamir Duberstein
@ 2025-05-29 13:24 ` Miguel Ojeda
2025-05-29 13:30 ` Miguel Ojeda
` (2 subsequent siblings)
3 siblings, 0 replies; 8+ messages in thread
From: Miguel Ojeda @ 2025-05-29 13:24 UTC (permalink / raw)
To: Tamir Duberstein
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Benno Lossin, rust-for-linux, linux-kernel
On Thu, May 29, 2025 at 3:11 PM Tamir Duberstein <tamird@gmail.com> wrote:
>
> Add a compile-time check that `*$ptr` is of the type of `$type->$($f)*`.
> Rename those placeholders for clarity.
I had a variation of v1 already applied locally, let me push and you
can take a look.
> +/// Helper for `container_of!`.
> +#[doc(hidden)]
> +pub fn assert_same_type<T>(_: T, _: T) {}
I meant to have a proper function, possibly "public" (not hidden I
mean). We can do that later, no worries.
Cheers,
Miguel
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v4] rust: check type of `$ptr` in `container_of!`
2025-05-29 13:11 [PATCH v4] rust: check type of `$ptr` in `container_of!` Tamir Duberstein
2025-05-29 13:24 ` Miguel Ojeda
@ 2025-05-29 13:30 ` Miguel Ojeda
2025-05-29 14:39 ` Tamir Duberstein
2025-05-29 15:31 ` Benno Lossin
2025-05-29 21:19 ` Miguel Ojeda
3 siblings, 1 reply; 8+ messages in thread
From: Miguel Ojeda @ 2025-05-29 13:30 UTC (permalink / raw)
To: Tamir Duberstein
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Benno Lossin, rust-for-linux, linux-kernel
On Thu, May 29, 2025 at 3:11 PM Tamir Duberstein <tamird@gmail.com> wrote:
>
> Rename those placeholders for clarity.
We can also put this in a separate one if it is OK with you.
Cheers,
Miguel
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v4] rust: check type of `$ptr` in `container_of!`
2025-05-29 13:30 ` Miguel Ojeda
@ 2025-05-29 14:39 ` Tamir Duberstein
2025-05-29 16:06 ` Miguel Ojeda
0 siblings, 1 reply; 8+ messages in thread
From: Tamir Duberstein @ 2025-05-29 14:39 UTC (permalink / raw)
To: Miguel Ojeda
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Benno Lossin, rust-for-linux, linux-kernel
On Thu, May 29, 2025 at 9:30 AM Miguel Ojeda
<miguel.ojeda.sandonis@gmail.com> wrote:
>
> On Thu, May 29, 2025 at 3:11 PM Tamir Duberstein <tamird@gmail.com> wrote:
> >
> > Rename those placeholders for clarity.
>
> We can also put this in a separate one if it is OK with you.
All fine. The only problem with the version you pushed is that it
evaluates $ptr twice, which was flagged by Alice in the v1 review.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v4] rust: check type of `$ptr` in `container_of!`
2025-05-29 13:11 [PATCH v4] rust: check type of `$ptr` in `container_of!` Tamir Duberstein
2025-05-29 13:24 ` Miguel Ojeda
2025-05-29 13:30 ` Miguel Ojeda
@ 2025-05-29 15:31 ` Benno Lossin
2025-05-29 21:19 ` Miguel Ojeda
3 siblings, 0 replies; 8+ messages in thread
From: Benno Lossin @ 2025-05-29 15:31 UTC (permalink / raw)
To: Tamir Duberstein, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich
Cc: rust-for-linux, linux-kernel
On Thu May 29, 2025 at 3:11 PM CEST, Tamir Duberstein wrote:
> Add a compile-time check that `*$ptr` is of the type of `$type->$($f)*`.
> Rename those placeholders for clarity.
>
> Given the incorrect usage:
>
>> diff --git a/rust/kernel/rbtree.rs b/rust/kernel/rbtree.rs
>> index 8d978c896747..6a7089149878 100644
>> --- a/rust/kernel/rbtree.rs
>> +++ b/rust/kernel/rbtree.rs
>> @@ -329,7 +329,7 @@ fn raw_entry(&mut self, key: &K) -> RawEntry<'_, K, V> {
>> 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) };
>> + let node = unsafe { container_of!(curr, Node<K, V>, key) };
>>
>> // SAFETY: `node` is a non-null node so it is valid by the type invariants.
>> match key.cmp(unsafe { &(*node).key }) {
>
> this patch produces the compilation error:
>
>> error[E0308]: mismatched types
>> --> rust/kernel/lib.rs:220:45
>> |
>> 220 | $crate::assert_same_type(field_ptr, (&raw const (*container_ptr).$($fields)*).cast_mut());
>> | ------------------------ --------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `*mut rb_node`, found `*mut K`
>> | | |
>> | | expected all arguments to be this `*mut bindings::rb_node` type because they need to match the type of this parameter
>> | arguments to this function are incorrect
>> |
>> ::: rust/kernel/rbtree.rs:270:6
>> |
>> 270 | impl<K, V> RBTree<K, V>
>> | - found this type parameter
>> ...
>> 332 | let node = unsafe { container_of!(curr, Node<K, V>, key) };
>> | ------------------------------------ in this macro invocation
>> |
>> = note: expected raw pointer `*mut bindings::rb_node`
>> found raw pointer `*mut K`
>> note: function defined here
>> --> rust/kernel/lib.rs:227:8
>> |
>> 227 | pub fn assert_same_type<T>(_: T, _: T) {}
>> | ^^^^^^^^^^^^^^^^ - ---- ---- this parameter needs to match the `*mut bindings::rb_node` type of parameter #1
>> | | |
>> | | parameter #2 needs to match the `*mut bindings::rb_node` type of this parameter
>> | parameter #1 and parameter #2 both reference this parameter `T`
>> = note: this error originates in the macro `container_of` (in Nightly builds, run with -Z macro-backtrace for more info)
In the future we could make this a proc-macro and improve the error
message by creating the function inline and setting the spans for the
parameter of the function to the spans coming from the input.
> Suggested-by: Alice Ryhl <aliceryhl@google.com>
> Link: https://lore.kernel.org/all/CAH5fLgh6gmqGBhPMi2SKn7mCmMWfOSiS0WP5wBuGPYh9ZTAiww@mail.gmail.com/
> Signed-off-by: Tamir Duberstein <tamird@gmail.com>
Reviewed-by: Benno Lossin <lossin@kernel.org>
---
Cheers,
Benno
> ---
> Changes in v4:
> - Revert back to v1 with assert_same_type extracted out of the macro. (Miguel Ojeda)
> - Drop Benno's RB since the implementation changed.
> - Rebase on rust-next.
> - Link to v3: https://lore.kernel.org/r/20250423-b4-container-of-type-check-v3-1-7994c56cf359@gmail.com
>
> Changes in v3:
> - Fix comment typo.
> - s/^;/ / in commit message and cover letter. (Miguel Ojeda)
> - Evaluate $ptr only once. (Alice Ryhl)
> - Link to v2: https://lore.kernel.org/r/20250412-b4-container-of-type-check-v2-1-f3cc9934c160@gmail.com
>
> Changes in v2:
> - Wrap in `if false` to improve unoptimized codegen. (Alice Ryhl)
> - Shrink implementation using an array literal instead of a function.
> - Link to v1: https://lore.kernel.org/r/20250411-b4-container-of-type-check-v1-1-08262ef67c95@gmail.com
> ---
> rust/kernel/lib.rs | 13 ++++++++++---
> 1 file changed, 10 insertions(+), 3 deletions(-)
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v4] rust: check type of `$ptr` in `container_of!`
2025-05-29 14:39 ` Tamir Duberstein
@ 2025-05-29 16:06 ` Miguel Ojeda
2025-05-29 16:55 ` Tamir Duberstein
0 siblings, 1 reply; 8+ messages in thread
From: Miguel Ojeda @ 2025-05-29 16:06 UTC (permalink / raw)
To: Tamir Duberstein
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Benno Lossin, rust-for-linux, linux-kernel
On Thu, May 29, 2025 at 4:40 PM Tamir Duberstein <tamird@gmail.com> wrote:
>
> All fine. The only problem with the version you pushed is that it
> evaluates $ptr twice, which was flagged by Alice in the v1 review.
Right -- this one also has the `&raw` too, and Benno provided the tag,
so let me take this one. The error is a tiny bit worse with the
`$crate::` in front now, but I think it is still good enough.
Thanks!
Cheers,
Miguel
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v4] rust: check type of `$ptr` in `container_of!`
2025-05-29 16:06 ` Miguel Ojeda
@ 2025-05-29 16:55 ` Tamir Duberstein
0 siblings, 0 replies; 8+ messages in thread
From: Tamir Duberstein @ 2025-05-29 16:55 UTC (permalink / raw)
To: Miguel Ojeda
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Benno Lossin, rust-for-linux, linux-kernel
On Thu, May 29, 2025 at 12:06 PM Miguel Ojeda
<miguel.ojeda.sandonis@gmail.com> wrote:
>
> On Thu, May 29, 2025 at 4:40 PM Tamir Duberstein <tamird@gmail.com> wrote:
> >
> > All fine. The only problem with the version you pushed is that it
> > evaluates $ptr twice, which was flagged by Alice in the v1 review.
>
> Right -- this one also has the `&raw` too, and Benno provided the tag,
> so let me take this one. The error is a tiny bit worse with the
> `$crate::` in front now, but I think it is still good enough.
Great! Thanks!
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v4] rust: check type of `$ptr` in `container_of!`
2025-05-29 13:11 [PATCH v4] rust: check type of `$ptr` in `container_of!` Tamir Duberstein
` (2 preceding siblings ...)
2025-05-29 15:31 ` Benno Lossin
@ 2025-05-29 21:19 ` Miguel Ojeda
3 siblings, 0 replies; 8+ messages in thread
From: Miguel Ojeda @ 2025-05-29 21:19 UTC (permalink / raw)
To: Tamir Duberstein
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Benno Lossin, rust-for-linux, linux-kernel
On Thu, May 29, 2025 at 3:11 PM Tamir Duberstein <tamird@gmail.com> wrote:
>
> Add a compile-time check that `*$ptr` is of the type of `$type->$($f)*`.
> Rename those placeholders for clarity.
>
> Given the incorrect usage:
>
> > diff --git a/rust/kernel/rbtree.rs b/rust/kernel/rbtree.rs
> > index 8d978c896747..6a7089149878 100644
> > --- a/rust/kernel/rbtree.rs
> > +++ b/rust/kernel/rbtree.rs
> > @@ -329,7 +329,7 @@ fn raw_entry(&mut self, key: &K) -> RawEntry<'_, K, V> {
> > 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) };
> > + let node = unsafe { container_of!(curr, Node<K, V>, key) };
> >
> > // SAFETY: `node` is a non-null node so it is valid by the type invariants.
> > match key.cmp(unsafe { &(*node).key }) {
>
> this patch produces the compilation error:
>
> > error[E0308]: mismatched types
> > --> rust/kernel/lib.rs:220:45
> > |
> > 220 | $crate::assert_same_type(field_ptr, (&raw const (*container_ptr).$($fields)*).cast_mut());
> > | ------------------------ --------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `*mut rb_node`, found `*mut K`
> > | | |
> > | | expected all arguments to be this `*mut bindings::rb_node` type because they need to match the type of this parameter
> > | arguments to this function are incorrect
> > |
> > ::: rust/kernel/rbtree.rs:270:6
> > |
> > 270 | impl<K, V> RBTree<K, V>
> > | - found this type parameter
> > ...
> > 332 | let node = unsafe { container_of!(curr, Node<K, V>, key) };
> > | ------------------------------------ in this macro invocation
> > |
> > = note: expected raw pointer `*mut bindings::rb_node`
> > found raw pointer `*mut K`
> > note: function defined here
> > --> rust/kernel/lib.rs:227:8
> > |
> > 227 | pub fn assert_same_type<T>(_: T, _: T) {}
> > | ^^^^^^^^^^^^^^^^ - ---- ---- this parameter needs to match the `*mut bindings::rb_node` type of parameter #1
> > | | |
> > | | parameter #2 needs to match the `*mut bindings::rb_node` type of this parameter
> > | parameter #1 and parameter #2 both reference this parameter `T`
> > = note: this error originates in the macro `container_of` (in Nightly builds, run with -Z macro-backtrace for more info)
>
> Suggested-by: Alice Ryhl <aliceryhl@google.com>
> Link: https://lore.kernel.org/all/CAH5fLgh6gmqGBhPMi2SKn7mCmMWfOSiS0WP5wBuGPYh9ZTAiww@mail.gmail.com/
> Signed-off-by: Tamir Duberstein <tamird@gmail.com>
Applied to `rust-next` -- thanks everyone!
[ We decided to go with a variation of v1 [1] that became v4, since it
seems like the obvious approach, the error messages seem good enough
and the debug performance should be fine, given the kernel is always
built with -O2.
In the future, we may want to make the helper non-hidden, with
proper documentation, for others to use.
[1] https://lore.kernel.org/rust-for-linux/CANiq72kQWNfSV0KK6qs6oJt+aGdgY=hXg=wJcmK3zYcokY1LNw@mail.gmail.com/
- Miguel ]
[ Added intra-doc link. - Miguel ]
Cheers,
Miguel
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2025-05-29 21:20 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-05-29 13:11 [PATCH v4] rust: check type of `$ptr` in `container_of!` Tamir Duberstein
2025-05-29 13:24 ` Miguel Ojeda
2025-05-29 13:30 ` Miguel Ojeda
2025-05-29 14:39 ` Tamir Duberstein
2025-05-29 16:06 ` Miguel Ojeda
2025-05-29 16:55 ` Tamir Duberstein
2025-05-29 15:31 ` Benno Lossin
2025-05-29 21:19 ` Miguel Ojeda
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).