rust-for-linux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [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).