Skip to contentSkip to conversation

rust: kernel: introduce `unsafe_precondition_assert!` macro

PATCH Superseded Ritvik Gupta 3 participants 4 messages Jul 31, 2025 – Aug 5, 2025 Rust

v3 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

PATCH v3 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 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 | 47 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+)
 create mode 100644 rust/kernel/safety.rs
rust/kernel/lib.rs +1 -0
index 11a6461e98da..7aab607dd879 100644
@@ -104,6 +104,7 @@
 pub mod print;
 pub mod rbtree;
 pub mod revocable;
+pub mod safety;
 pub mod security;
 pub mod seq_file;
 pub mod sizes;
rust/kernel/safety.rs new file +47 -0

47 lines not on this page · raw message

base-commit: dff64b072708ffef23c117fa1ee1ea59eb417807

Signature · 1 line
2.50.1
#1 lore raw

rust/kernel/safety.rs line 16

Quoted 3 lines · Ritvik Gupta
rust/kernel/safety.rs new file +2 -0
+/// /// - `buf` must be non-null.
+/// /// - `buf` must be 16-byte aligned.

We don't know since the full body is not shown, but it is likely this would need to also be a valid pointer, i.e. it may be an uncommon example.

Perhaps we could show one of the conditional cases, i.e. the "if buf is non-null, then it must be valid." cases. That could also be a nice excuse to also introduce an implies() function if an example allows for it. But we can do that later on, no worries.

More importantly, could we have a user of the macro introduced in a second patch so that it gets already used?

Thanks for the patch!

Cheers,
Miguel

#2 lore raw
Quoted 8 lines · Miguel Ojeda

rust/kernel/safety.rs line 16

Quoted 3 lines · Ritvik Gupta
rust/kernel/safety.rs new file +2 -0
+/// /// - `buf` must be non-null.
+/// /// - `buf` must be 16-byte aligned.

We don't know since the full body is not shown, but it is likely this would need to also be a valid pointer, i.e. it may be an uncommon example.

I believe this is a valid use-case for unsafe_precondition_assert!. Should we add similar example?

```cpu.rs
/// Creates a new [`CpuId`] from the given `id` without checking bounds.
///
/// # Safety
///
/// The caller must ensure that `id` is a valid CPU ID (i.e., `0 <= id < nr_cpu_ids()`).
#[inline]
pub unsafe fn from_u32_unchecked(id: u32) -> Self {
    debug_assert!(id < nr_cpu_ids());

    // Ensure the `id` fits in an [`i32`] as it's also representable that way.
    debug_assert!(id <= i32::MAX as u32);

    // INVARIANT: The function safety guarantees `id` is a valid CPU id.
    Self(id)
}
```
Quoted 2 lines

More importantly, could we have a user of the macro introduced in a second patch so that it gets already used?

I believe the debug_assert! calls inside the unsafe fn (excluding 'const fn' and 'CONFIG_RUST_OVERFLOW_CHECKS' flag) are the intended targets for unsafe_precondition_assert!.

A quick grep (git grep -B 15 -A 10 "debug_assert"),
I could find 6 relevant callers in alloc/kvec.rs (2) and cpu.rs (4), unless I'm missing something.

I'll send another patch for this, after getting the example correct. Thanks for the feedback :)

#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 dff64b072708ffef23c117fa1ee1ea59eb417807]

url:    https://github.com/intel-lab-lkp/linux/commits/Ritvik-Gupta/rust-kernel-introduce-unsafe_precondition_assert-macro/20250731-191444
base:   dff64b072708ffef23c117fa1ee1ea59eb417807
patch link:    https://lore.kernel.org/r/20250731111234.28602-1-ritvikfoss%40gmail.com
patch subject: [PATCH v3] rust: kernel: introduce `unsafe_precondition_assert!` macro
config: x86_64-rhel-9.4-rust (https://download.01.org/0day-ci/archive/20250805/[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/20250805/[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: cannot find macro `unsafe_precondition_assert` in this scope

--> rust/doctests_kernel_generated.rs:8012:5
|
8012 | unsafe_precondition_assert!(!buf.is_null(), "buf must not be null");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
::: /opt/cross/rustc-1.88.0-bindgen-0.72.0/rustup/toolchains/1.88.0-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ub_checks.rs:52:1 |
52 | macro_rules! assert_unsafe_precondition {
| --------------------------------------- similarly named macro assert_unsafe_precondition defined here
|
help: a macro with a similar name exists
|
8012 - unsafe_precondition_assert!(!buf.is_null(), "buf must not be null");
8012 + assert_unsafe_precondition!(!buf.is_null(), "buf must not be null");
|
help: consider importing this macro
|
3 + use kernel::unsafe_precondition_assert;
|
--

>> error: cannot find macro `unsafe_precondition_assert` in this scope

--> rust/doctests_kernel_generated.rs:8013:5
|
8013 | unsafe_precondition_assert!((buf as usize) % 16 == 0, "buf must be 16-byte aligned");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
::: /opt/cross/rustc-1.88.0-bindgen-0.72.0/rustup/toolchains/1.88.0-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ub_checks.rs:52:1 |
52 | macro_rules! assert_unsafe_precondition {
| --------------------------------------- similarly named macro assert_unsafe_precondition defined here
|
help: a macro with a similar name exists
|
8013 - unsafe_precondition_assert!((buf as usize) % 16 == 0, "buf must be 16-byte aligned");
8013 + assert_unsafe_precondition!((buf as usize) % 16 == 0, "buf must be 16-byte aligned");
|
help: consider importing this macro
|
3 + use kernel::unsafe_precondition_assert;
|
--

>> error: cannot find macro `unsafe_precondition_assert` in this scope

--> rust/doctests_kernel_generated.rs:8014:5
|
8014 | unsafe_precondition_assert!(
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
::: /opt/cross/rustc-1.88.0-bindgen-0.72.0/rustup/toolchains/1.88.0-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ub_checks.rs:52:1 |
52 | macro_rules! assert_unsafe_precondition {
| --------------------------------------- similarly named macro assert_unsafe_precondition defined here
|
help: a macro with a similar name exists
|
8014 - unsafe_precondition_assert!(
8014 + assert_unsafe_precondition!(
|
help: consider importing this macro
|
3 + use kernel::unsafe_precondition_assert;
|

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