lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <242d0107-8e2b-4856-8f4c-1d5351fdaad8@proton.me>
Date: Mon, 05 Aug 2024 19:02:28 +0000
From: Benno Lossin <benno.lossin@...ton.me>
To: Matt Gilbride <mattgilbride@...gle.com>, Miguel Ojeda <ojeda@...nel.org>, Alex Gaynor <alex.gaynor@...il.com>, Wedson Almeida Filho <wedsonaf@...il.com>, Boqun Feng <boqun.feng@...il.com>, Gary Guo <gary@...yguo.net>, Björn Roy Baron <bjorn3_gh@...tonmail.com>, Andreas Hindborg <a.hindborg@...sung.com>, Alice Ryhl <aliceryhl@...gle.com>, Greg Kroah-Hartman <gregkh@...uxfoundation.org>, Arve Hjønnevåg <arve@...roid.com>, Todd Kjos <tkjos@...roid.com>, Martijn Coenen <maco@...roid.com>, Joel Fernandes <joel@...lfernandes.org>, Carlos Llamas <cmllamas@...gle.com>, Suren Baghdasaryan <surenb@...gle.com>, Christian Brauner <brauner@...nel.org>
Cc: Rob Landley <rob@...dley.net>, Davidlohr Bueso <dave@...olabs.net>, Michel Lespinasse <michel@...pinasse.org>, rust-for-linux@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: Re: [PATCH v8 2/6] rust: rbtree: add red-black tree implementation backed by the C version

On 27.07.24 22:30, Matt Gilbride wrote:
> diff --git a/rust/kernel/rbtree.rs b/rust/kernel/rbtree.rs
> new file mode 100644
> index 000000000000..74c53e4d5c00
> --- /dev/null
> +++ b/rust/kernel/rbtree.rs
> @@ -0,0 +1,432 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +//! Red-black trees.
> +//!
> +//! C header: [`include/linux/rbtree.h`](srctree/include/linux/rbtree.h)
> +//!
> +//! Reference: <https://www.kernel.org/doc/html/latest/core-api/rbtree.html>
> +
> +use crate::{alloc::Flags, bindings, container_of, error::Result, prelude::*};
> +use alloc::boxed::Box;
> +use core::{
> +    cmp::{Ord, Ordering},
> +    marker::PhantomData,
> +    mem::MaybeUninit,
> +    ptr::{addr_of_mut, NonNull},
> +};
> +
> +/// A red-black tree with owned nodes.
> +///
> +/// It is backed by the kernel C red-black trees.
> +///
> +/// # Invariants
> +///
> +/// Non-null parent/children pointers stored in instances of the `rb_node` C struct are always
> +/// valid, and pointing to a field of our internal representation of a node.

I think we should standardize that `Invariants` and `Safety` sections
are put last. This is because people reading the HTML version are
probably not interested in the inner workings. This also makes it
possible to have the invariants and the struct definition on the same
screen.

> +///
> +/// # Examples

[...]

> +/// ```
> +pub struct RBTree<K, V> {
> +    root: bindings::rb_root,

It has been a while, so I might have already asked this, but do we need
`Opaque` here? We would need it, if C changes anything inside `root`
while Rust holds a `&RBTree` or `&mut RBTree`.
I don't think that this is the case (ie we don't need `Opaque`), but I
am not sure.

> +    _p: PhantomData<Node<K, V>>,
> +}
> +

[...]

> +    /// Inserts a new node into the tree.
> +    ///
> +    /// It overwrites a node if one already exists with the same key and returns it (containing the
> +    /// key/value pair). Returns [`None`] if a node with the same key didn't already exist.
> +    ///
> +    /// This function always succeeds.
> +    pub fn insert(&mut self, RBTreeNode { node }: RBTreeNode<K, V>) -> Option<RBTreeNode<K, V>> {
> +        let node = Box::into_raw(node);
> +        // SAFETY: `node` is valid at least until we call `Box::from_raw`, which only happens when
> +        // the node is removed or replaced.
> +        let node_links = unsafe { addr_of_mut!((*node).links) };
> +
> +        // The parameters of `rb_link_node` are as follows:

Can you write `bindings::rb_link_node`?

> +        // - `node`: A pointer to an uninitialized node being inserted.
> +        // - `parent`: A pointer to an existing node in the tree. One of its child pointers must be
> +        //          null, and `node` will become a child of `parent` by replacing that child pointer
> +        //          with a pointer to `node`.
> +        // - `rb_link`: A pointer to either the left-child or right-child field of `parent`. This
> +        //          specifies which child of `parent` should hold `node` after this call. The
> +        //          value of `*rb_link` must be null before the call to `rb_link_node`. If the
> +        //          red/black tree is empty, then it’s also possible for `parent` to be null. In
> +        //          this case, `rb_link` is a pointer to the `root` field of the red/black tree.
> +        //
> +        // We will traverse the tree looking for a node that has a null pointer as its child,
> +        // representing an empty subtree where we can insert our new node. We need to make sure
> +        // that we preserve the ordering of the nodes in the tree. In each iteration of the loop
> +        // we store `parent` and `child_field_of_parent`, and the new `node` will go somewhere
> +        // in the subtree of `parent` that `child_field_of_parent` points at. Once
> +        // we find an empty subtree, we can insert the new node using `rb_link_node`.
> +        let mut parent = core::ptr::null_mut();
> +        let mut child_field_of_parent: &mut *mut bindings::rb_node = &mut self.root.rb_node;
> +        while !child_field_of_parent.is_null() {
> +            parent = *child_field_of_parent;
> +
> +            // We need to determine whether `node` should be the left or right child of `parent`,
> +            // so we will compare with the `key` field of `parent` a.k.a. `this` below.
> +            //
> +            // 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!(parent, Node<K, V>, links) };
> +
> +            // SAFETY: `this` is a non-null node so it is valid by the type invariants. `node` is
> +            // valid until the node is removed.
> +            match unsafe { (*node).key.cmp(&(*this).key) } {
> +                // We would like `node` to be the left child of `parent`.  Move to this child to check
> +                // whether we can use it, or continue searching, at the next iteration.
> +                //
> +                // SAFETY: `parent` is a non-null node so it is valid by the type invariants.
> +                Ordering::Less => child_field_of_parent = unsafe { &mut (*parent).rb_left },
> +                // We would like `node` to be the right child of `parent`.  Move to this child to check
> +                // whether we can use it, or continue searching, at the next iteration.
> +                //
> +                // SAFETY: `parent` is a non-null node so it is valid by the type invariants.
> +                Ordering::Greater => child_field_of_parent = unsafe { &mut (*parent).rb_right },
> +                Ordering::Equal => {
> +                    // There is an existing node in the tree with this key, and that node is
> +                    // parent.  Thus, we are replacing parent with a new node.

Missing `` around "parent", double space after '.'.

> +                    //
> +                    // INVARIANT: We are replacing an existing node with a new one, which is valid.
> +                    // It remains valid because we "forgot" it with `Box::into_raw`.
> +                    // SAFETY: All pointers are non-null and valid.
> +                    unsafe { bindings::rb_replace_node(parent, node_links, &mut self.root) };
> +
> +                    // INVARIANT: The node is being returned and the caller may free it, however,
> +                    // it was removed from the tree. So the invariants still hold.
> +                    return Some(RBTreeNode {
> +                        // SAFETY: `this` was a node in the tree, so it is valid.
> +                        node: unsafe { Box::from_raw(this.cast_mut()) },
> +                    });
> +                }
> +            }
> +        }

[...]

> +struct Node<K, V> {
> +    links: bindings::rb_node,

Same question as with `rb_root`, do we need `Opaque`?


Otherwise the patch looks good.

---
Cheers,
Benno

> +    key: K,
> +    value: V,
> +}
> 
> --
> 2.46.0.rc1.232.g9752f9e123-goog
> 


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ