Re: [TECH TOPIC] Rust for Linux

Miguel Ojeda
2021-07-07T15:15:13Z

On Wed, Jul 7, 2021 at 4:08 PM James Bottomley
<James.Bottomley@hansenpartnership.com> wrote:
>
> UB is Undefined Behaviour, right? C plus the memory model should mean
> we don't have that in the kernel, although that's enforced by
> inspection and checking rather than the compiler.

Yes, it is Undefined Behavior. I am sure you know, but just in case:
it covers things like the usual out-of-bounds accesses, using objects
after their lifetime has ended, data races, etc., plus quite a few
other things.

There are 200+ instances of UB listed in the Annex J.2 list of the C
standard [1]. SEI CERT also has a nice list [2].

On its own, UB is not bad. Nowadays, some instances of UB are used by
optimizers to give us the performance we all love.

However, the problem comes when we, as humans, mistakenly introduce
UB. Even someone that is very knowledgeable about C introduces UB from
time to time. We all do. The reason is simple: reasoning about UB is
typically non-local, e.g. we may be doing a change in some function
that changes a pointer, and that change on its own may be fine, but we
did not account for some invariant in another function that uses the
pointer.

Other times UB appears because the optimizer had different assumptions
than the person writing the code / project / environment, e.g. the
`-fno-delete-null-pointer-checks` issue we had in the kernel a decade
ago, where the optimizer removes a branch because you already accessed
a pointer.

In summary, relying on inspection to avoid UB is a losing battle. That
is why many tools appeared throughout the decades to attack different
parts: Valgrind (Memcheck, Helgrind, DRD...), ASAN, UBSAN, Miri, etc.

Rust, like C, has UB. The difference is that Rust has a safe subset
where UB is statically guaranteed to not occur (as long as the unsafe
code is sound). This is key: you "only" need to make sure the unsafe
parts are not breaking the rules, and if that is true, Rust guarantees
the safe code does not break them either.

This means the work of inspection / checking / running UBSAN and
friends, etc. can be focused on the unsafe bits.

[1] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2596.pdf
[2] https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior.

> I'm not sure I get the point here: all the kernel refcount models are
> explicitly multi-threaded, because we usually expect multiple CPU
> threads to be using objects simultaneously ... it's why the base
> implementation, kref, uses atomics. That's not to say we don't have
> single threaded use cases ... it's just that's not what's commonly
> used.

Yes, `Rc` is a type meant for single-threaded reference-counting
scenarios. For multi-threaded scenarios, Rust provides `Arc` instead.
It still guarantees no UB and no data races.

This is actually a good example of another benefit. `Rc` is there
because there is a performance advantage when you do not need to share
it among threads (you do not need to use atomics) -- and Rust checks
you do not do so. In C, you can still have an `Rc`, but you would not
have a compile-time guarantee that it is not shared. So in C you may
decide to avoid your single-threaded `Rc` and use `Arc` "just in case"
-- and, in fact, this is the only one C++ has (`std::shared_ptr`), and
even then, it does not statically prevent UB.

> That does beg another question which I couldn't find the answer to in
> the base docs: the Rust Rc<T> is saturation protected, isn't it? or
> would the rust implementation inherit that from the kernel?

We can do both: we can introduce new types with the precise semantics
we need in pure Rust, but we can also "abstract" C facilities.

For instance, we have a `Ref` type that is similar to `Arc` but reuses
the `refcount_t` from C and introduces saturation instead of aborting
[3]

Another example are the red-black trees that abstract the C implementation [4].

[3] https://github.com/Rust-for-Linux/linux/blob/rust/rust/kernel/sync/arc.rs
[4] https://github.com/Rust-for-Linux/linux/blob/rust/rust/kernel/rbtree.rs

Cheers,
Miguel