In order to share some of the things I've been doing over Rust for Linux, I decided I would start a small series of tiny posts that demystify and detail very simple operations that can be confusing when doing development for RFL.

Rust Features

Rust features go through a lifecycle where they can begin as "unstable", and then eventually stabilized once Rust maintainers can guarantee that it will henceforth be backwards compatible, and free of memory errors (if unsafe {} is used).

Our example here is Box::try_new, which is still nightly/experimental. Unstable features can be used in library crates if you declare that a module is allowed to use anything behind their feature gate. Box::try_new is gated behind the allocator_api feature, meaning that if you want to use it, you need to declare that you use it at the root module of your library crate:

//! My library crate

#![feature(allocator_api)]

// You also cannot use that import unless you unlock the `allocator_api` feature gate
use core::alloc::AllocError;

pub fn make_a_new_box() -> Result<Box<Vec<i32>>, AllocError> {
  Box::try_new(Vec::new())
}

Of course, you also need a nightly toolchain that allows you to have said feature.

What of binary crates? Well, not only do you need to use a nightly toolchain, you also need to explicitly declare in the command line that you're allowing a feature. For a binary crate, the list of allowed features is enabled, so you do not need the feature attribute.

Back to Rust for Linux

So, why does this matter to RFL?

In the kernel, allocation is never guaranteed. You are in the kernel, so you are the huge program managing the memory, and, sometimes, there is no memory left, and you should be able to handle that (usually by gracefully unwinding and destroying all your resources, or aborting a callback, or whatever). So, if you want to Box something, you should use try_new (in fact, Box::new does not exist in RFL). Of course, if you're going to do special things with that Box, you may use other methods, but let's pretend we just want to try_new.

As of the writing of this blog post, if you pull the rust-next branch and try to write a module with a Box::try_new, it will fail. Adding the feature attribute will not help of course, because modules are not library crates. You need to add the allocator_api to the list of allow_features in the command line.

Thankfully, we are allowed to do that (see Unstable features stabilized) for new modules that can be upstreamed. For example, in the null block driver patchset, Andreas Hindborg adds the allocator_api so he can use Box::try_new as well.

The precise file to add that is scripts/Makefile.build:

# Compile Rust sources (.rs)
# ---------------------------------------------------------------------------

rust_allowed_features := new_uninit,allocator_api

With that, you have a new allowed feature available.