]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
rust: safety: introduce `unsafe_precondition_assert!` macro
authorRitvik Gupta <ritvikfoss@gmail.com>
Tue, 7 Oct 2025 21:50:28 +0000 (03:20 +0530)
committerMiguel Ojeda <ojeda@kernel.org>
Mon, 2 Feb 2026 07:10:48 +0000 (08:10 +0100)
Introduce a new `safety` module containing `unsafe_precondition_assert!`
macro. It is a wrapper around `debug_assert!`, intended for validating
preconditions 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>
Reviewed-by: Benno Lossin <lossin@kernel.org>
Link: https://patch.msgid.link/20251007215034.213779-1-ritvikfoss@gmail.com
[ Added trailing periods, intra-doc link, "a" in "is a no-op" and `()`
  to function reference. Removed plural in assertion message and title
  of macro. Reworded slightly. - Miguel ]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
rust/kernel/lib.rs
rust/kernel/safety.rs [new file with mode: 0644]

index 996affce2c9e2ff6ad54783e66c9935e2c1ab66f..696f62f85eb5f5e11e63cabf0d2ff6f3046dbd3e 100644 (file)
@@ -135,6 +135,7 @@ pub mod pwm;
 pub mod rbtree;
 pub mod regulator;
 pub mod revocable;
+pub mod safety;
 pub mod scatterlist;
 pub mod security;
 pub mod seq_file;
diff --git a/rust/kernel/safety.rs b/rust/kernel/safety.rs
new file mode 100644 (file)
index 0000000..c1c6bd0
--- /dev/null
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Safety related APIs.
+
+/// Checks that a precondition of an unsafe function is followed.
+///
+/// The check is enabled at runtime if debug assertions (`CONFIG_RUST_DEBUG_ASSERTIONS`)
+/// are enabled. Otherwise, this macro is a no-op.
+///
+/// # Examples
+///
+/// ```no_run
+/// use kernel::unsafe_precondition_assert;
+///
+/// struct RawBuffer<T: Copy, const N: usize> {
+///     data: [T; N],
+/// }
+///
+/// impl<T: Copy, const N: usize> RawBuffer<T, N> {
+///     /// # Safety
+///     ///
+///     /// The caller must ensure that `index` is less than `N`.
+///     unsafe fn set_unchecked(&mut self, index: usize, value: T) {
+///         unsafe_precondition_assert!(
+///             index < N,
+///             "RawBuffer::set_unchecked() requires index ({index}) < N ({N})"
+///         );
+///
+///         // SAFETY: By the safety requirements of this function, `index` is valid.
+///         unsafe {
+///             *self.data.get_unchecked_mut(index) = value;
+///         }
+///     }
+/// }
+/// ```
+///
+/// # 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, $crate::prelude::fmt!($($arg)+))
+    };
+
+    (@inner $cond:expr, $msg:expr) => {
+        ::core::debug_assert!($cond, "unsafe precondition violated: {}", $msg)
+    };
+}