linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3] rust: kernel: introduce `unsafe_precondition_assert!` macro
@ 2025-07-31 11:12 Ritvik Gupta
  2025-07-31 11:42 ` Miguel Ojeda
  2025-08-05  0:17 ` kernel test robot
  0 siblings, 2 replies; 4+ messages in thread
From: Ritvik Gupta @ 2025-07-31 11:12 UTC (permalink / raw)
  To: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich
  Cc: skhan, linux-kernel, rust-for-linux

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.

Suggested-by: Miguel Ojeda <ojeda@kernel.org>
Link: https://github.com/Rust-for-Linux/linux/issues/1162
Link: https://rust-for-linux.zulipchat.com/#narrow/channel/291566-Library/topic/.60unsafe_precondition_assert.60.20macro/with/528457452
Signed-off-by: Ritvik Gupta <ritvikfoss@gmail.com>
---

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/20250716045957.39732-1-ritvikfoss@gmail.com/

---
 rust/kernel/lib.rs    |  1 +
 rust/kernel/safety.rs | 47 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+)
 create mode 100644 rust/kernel/safety.rs

diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 11a6461e98da..7aab607dd879 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -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;
diff --git a/rust/kernel/safety.rs b/rust/kernel/safety.rs
new file mode 100644
index 000000000000..f591eed6da77
--- /dev/null
+++ b/rust/kernel/safety.rs
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Safety related APIs.
+
+/// Checks that preconditions of an unsafe function are followed.
+///
+/// The check is enabled at runtime if debug assertions (`CONFIG_RUST_DEBUG_ASSERTIONS`)
+/// are enabled. Otherwise, this macro is no-op.
+///
+/// # Examples
+///
+/// ```
+/// /// # Safety
+/// ///
+/// /// - `buf` must be non-null.
+/// /// - `buf` must be 16-byte aligned.
+/// /// - `len` must be multiple of [`PAGE_SIZE`].
+/// unsafe fn foo(buf: *const u8, len: usize) {
+///     unsafe_precondition_assert!(!buf.is_null(), "buf must not be null");
+///     unsafe_precondition_assert!((buf as usize) % 16 == 0, "buf must be 16-byte aligned");
+///     unsafe_precondition_assert!(
+///         len % PAGE_SIZE == 0,
+///         "len ({}) must be multiple of PAGE_SIZE ({})",
+///         len,
+///         PAGE_SIZE
+///     );
+///     // ...
+/// }
+/// ```
+///
+/// # Panics
+///
+/// Panics if the expression is evaluated to `false` at runtime.
+///
+#[macro_export]
+macro_rules! unsafe_precondition_assert {
+    ($cond:expr $(,)?) => {
+        $crate::unsafe_precondition_assert!(@inner $cond, ::core::stringify!($cond))
+    };
+
+    ($cond:expr, $($arg:tt)+) => {
+        $crate::unsafe_precondition_assert!(@inner $cond, ::core::format_args!($($arg)+))
+    };
+
+    (@inner $cond:expr, $msg:expr) => {
+        ::core::debug_assert!($cond, "unsafe precondition(s) violated: {}", $msg) };
+}

base-commit: dff64b072708ffef23c117fa1ee1ea59eb417807
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH v3] rust: kernel: introduce `unsafe_precondition_assert!` macro
  2025-07-31 11:12 [PATCH v3] rust: kernel: introduce `unsafe_precondition_assert!` macro Ritvik Gupta
@ 2025-07-31 11:42 ` Miguel Ojeda
  2025-08-01 13:49   ` Ritvik Gupta
  2025-08-05  0:17 ` kernel test robot
  1 sibling, 1 reply; 4+ messages in thread
From: Miguel Ojeda @ 2025-07-31 11:42 UTC (permalink / raw)
  To: Ritvik Gupta
  Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, skhan, linux-kernel,
	rust-for-linux

On Thu, Jul 31, 2025 at 1:12 PM Ritvik Gupta <ritvikfoss@gmail.com> wrote:
>
> +/// /// - `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

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v3] rust: kernel: introduce `unsafe_precondition_assert!` macro
  2025-07-31 11:42 ` Miguel Ojeda
@ 2025-08-01 13:49   ` Ritvik Gupta
  0 siblings, 0 replies; 4+ messages in thread
From: Ritvik Gupta @ 2025-08-01 13:49 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, skhan, linux-kernel,
	rust-for-linux

On Thu, Jul 31, 2025 at 01:42:42PM +0200, Miguel Ojeda wrote:
> On Thu, Jul 31, 2025 at 1:12 PM Ritvik Gupta <ritvikfoss@gmail.com> wrote:
> >
> > +/// /// - `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)
}
```

> 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 :)

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v3] rust: kernel: introduce `unsafe_precondition_assert!` macro
  2025-07-31 11:12 [PATCH v3] rust: kernel: introduce `unsafe_precondition_assert!` macro Ritvik Gupta
  2025-07-31 11:42 ` Miguel Ojeda
@ 2025-08-05  0:17 ` kernel test robot
  1 sibling, 0 replies; 4+ messages in thread
From: kernel test robot @ 2025-08-05  0:17 UTC (permalink / raw)
  To: Ritvik Gupta, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich
  Cc: llvm, oe-kbuild-all, skhan, linux-kernel, rust-for-linux

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/202508050756.oFg4cjPu-lkp@intel.com/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/202508050756.oFg4cjPu-lkp@intel.com/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 <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202508050756.oFg4cjPu-lkp@intel.com/

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;
   |

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

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2025-08-05  0:18 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-07-31 11:12 [PATCH v3] rust: kernel: introduce `unsafe_precondition_assert!` macro Ritvik Gupta
2025-07-31 11:42 ` Miguel Ojeda
2025-08-01 13:49   ` Ritvik Gupta
2025-08-05  0:17 ` kernel test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).