Skip to contentSkip to conversation

rust: kernel: introduce `unsafe_precondition_assert!` macro

PATCH Superseded Ritvik Gupta 3 participants 6 messages Aug 8, 2025 – Aug 12, 2025 Rust

v4 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

PATCH v4 1/1 rust: kernel: introduce `unsafe_precondition_assert!` macro

Introduce a new safety module containing unsafe_precondition_assert! macro. It is a wrapper around debug_assert!, intended for validating pre-conditions of unsafe function.

When CONFIG_RUST_DEBUG_ASSERTIONS flag is enabled, this macro performs runtime checks to ensure that the preconditions for unsafe function hold. Otherwise, the macro is a no-op.

---

Changes in v4:
- Change doc example
- Add no_run attribute to the doc example
- Link to v3: https://lore.kernel.org/rust-for-linux/[email protected]/

Changes in v3:
- Change doc example
- Link to v2: https://lore.kernel.org/all/20250730181420.6979b4f1@eugeo/T/#m9cd35a8fc02a18bd03934c7ecdcffe8667b5fbbd

Changes in v2:
- Wrap debug_assert! internally instead of using pr_err! with assert! + `cfg!(debug_assertions)
- Print “unsafe precondition(s) violated” only on assertion failure (no longer always printed)
- Use # Safety section instead of comment in the example
- Rename module-level doc
- Link to v1: https://lore.kernel.org/rust-for-linux/[email protected]/

---
 rust/kernel/lib.rs    |  1 +
 rust/kernel/safety.rs | 48 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 49 insertions(+)
 create mode 100644 rust/kernel/safety.rs
rust/kernel/lib.rs +1 -0
index ed53169e795c..5eb301685ce8 100644
@@ -113,6 +113,7 @@
 pub mod rbtree;
 pub mod regulator;
 pub mod revocable;
+pub mod safety;
 pub mod security;
 pub mod seq_file;
 pub mod sizes;
rust/kernel/safety.rs new file +48 -0

48 lines not on this page · raw message

base-commit: 37816488247ddddbc3de113c78c83572274b1e2e

Signature · 1 line
2.50.1
reviewer
#1 lore raw
Quoted 13 lines · Ritvik Gupta

Introduce a new safety module containing unsafe_precondition_assert! macro. It is a wrapper around debug_assert!, intended for validating pre-conditions of unsafe function.

When CONFIG_RUST_DEBUG_ASSERTIONS flag is enabled, this macro performs runtime checks to ensure that the preconditions for unsafe function hold. Otherwise, the macro is a no-op.

rust/kernel/safety.rs line 43

Quoted 2 lines
rust/kernel/safety.rs new file +2 -0
+    ($cond:expr, $($arg:tt)+) => {
+        $crate::unsafe_precondition_assert!(@inner $cond, ::core::format_args!($($arg)+))

Tamir, taking your fmt series into account, what's the correct replacement for ::core::format_args! here?

Alice

#2 lore raw
Quoted 5 lines

rust/kernel/safety.rs line 43

Quoted 2 lines
rust/kernel/safety.rs new file +2 -0
+    ($cond:expr, $($arg:tt)+) => {
+        $crate::unsafe_precondition_assert!(@inner $cond, ::core::format_args!($($arg)+))

Tamir, taking your fmt series into account, what's the correct replacement for ::core::format_args! here?

Whoops! I wasn't aware of the fmt-series! Thanks for mentioning it :)

After a quick search, kernel::prelude::fmt! type/macro [1,2] seems to be the relevant replacement. So, the line would look like:

	`$crate::unsafe_precondition_assert!(@inner $cond, $crate::prelude::fmt!($($arg)+))`

Does that sound right?

[1]: https://github.com/Rust-for-Linux/linux/blob/8f5ae30d69d7543eee0d70083daf4de8fe15d585/rust/kernel/prelude.rs#L36
[2]: https://lore.kernel.org/rust-for-linux/[email protected]/

#3 lore raw
In reply to Ritvik Gupta
kernel test robot noticed the following build errors:

Hi Ritvik,

kernel test robot noticed the following build errors:

[auto build test ERROR on 37816488247ddddbc3de113c78c83572274b1e2e]

url:    https://github.com/intel-lab-lkp/linux/commits/Ritvik-Gupta/rust-kernel-introduce-unsafe_precondition_assert-macro/20250809-032122
base:   37816488247ddddbc3de113c78c83572274b1e2e
patch link:    https://lore.kernel.org/r/20250808192005.209188-1-ritvikfoss%40gmail.com
patch subject: [PATCH v4] rust: kernel: introduce `unsafe_precondition_assert!` macro
config: x86_64-rhel-9.4-rust (https://download.01.org/0day-ci/archive/20250812/[email protected]/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
rustc: rustc 1.88.0 (6b00bc388 2025-06-23)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250812/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

>> error[E0423]: cannot initialize a tuple struct which contains private fields

--> rust/doctests_kernel_generated.rs:8841:5
|
8841 | CpuId(id)
| ^^^^^
|
note: constructor is not visible here due to private fields --> rust/kernel/cpu.rs:47:18
|
47 | pub struct CpuId(u32);
| ^^^ private field
help: you might have meant to use an associated function to build this type |
8841 - CpuId(id)
8841 + CpuId::from_i32_unchecked(_)
|
8841 - CpuId(id)
8841 + CpuId::from_u32_unchecked(_)
|
8841 - CpuId(id)
8841 + CpuId::current()
|

Signature · 2 lines
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
#4 lore raw

If someone's referring to it in the future, this was doctest issue.

It’s actually the second time I’ve hit it.
On my end, this error wasn't occurring when compiling the kernel.

What I was missing:
1. Enable Kernel Hacking > Kernel Testing and Coverage > KUnit
2. Enable Doctest in Rust hacking > Doctests for the 'kernel' crate

I can now reproduce capture the issue locally.
Won't happen again :)

#5 lore raw
In reply to Ritvik Gupta
Quoted 12 lines
rust/kernel/safety.rs new file +12 -0
+/// # Examples
+///
+/// ```no_run
+/// # use kernel::unsafe_precondition_assert;
+/// # use kernel::cpu::{nr_cpu_ids, CpuId};
+/// /// Creates a [`CpuId`] from the given `id` without bound checks.
+/// ///
+/// /// # Safety
+/// ///
+/// /// The caller must ensure that `id` is a valid CPU ID (i.e, `0 <= id < nr_cpu_ids()`).
+/// unsafe fn new_cpu_id_unchecked(id: i32) -> CpuId {
+///     let max_cpus = nr_cpu_ids();

rust/kernel/safety.rs line 31

Quoted 10 lines
rust/kernel/safety.rs new file +10 -0
+///
+///     unsafe_precondition_assert!(id >= 0, "id ({}) must be positive", id);
+///
+///     unsafe_precondition_assert!(
+///         id < max_cpus, "id ({}) must be less than total CPUs ({})", id, max_cpus
+///     );
+///
+///     CpuId(id)
+/// }
+/// ```

The example I've included is incorrect because CpuId inner field is private, so it can't be constructed this way.

CpuId::from_i32_unchecked() exists, using it here would make the example a trivial wrapper around that method, that would be unnecessary and confusing. Also, I wasn't sure about the doctest config when I wrote it.

I'll send v5 with correct and much better example. Plz ignore it. Sorry for the noise.