Skip to main content

kernel/
safety.rs

1// SPDX-License-Identifier: GPL-2.0
2
3//! Safety related APIs.
4
5/// Checks that a precondition of an unsafe function is followed.
6///
7/// The check is enabled at runtime if debug assertions (`CONFIG_RUST_DEBUG_ASSERTIONS`)
8/// are enabled. Otherwise, this macro is a no-op.
9///
10/// # Examples
11///
12/// ```no_run
13/// use kernel::unsafe_precondition_assert;
14///
15/// struct RawBuffer<T: Copy, const N: usize> {
16///     data: [T; N],
17/// }
18///
19/// impl<T: Copy, const N: usize> RawBuffer<T, N> {
20///     /// # Safety
21///     ///
22///     /// The caller must ensure that `index` is less than `N`.
23///     unsafe fn set_unchecked(&mut self, index: usize, value: T) {
24///         unsafe_precondition_assert!(
25///             index < N,
26///             "RawBuffer::set_unchecked() requires index ({index}) < N ({N})"
27///         );
28///
29///         // SAFETY: By the safety requirements of this function, `index` is valid.
30///         unsafe {
31///             *self.data.get_unchecked_mut(index) = value;
32///         }
33///     }
34/// }
35/// ```
36///
37/// # Panics
38///
39/// Panics if the expression is evaluated to [`false`] at runtime.
40#[macro_export]
41macro_rules! unsafe_precondition_assert {
42    ($cond:expr $(,)?) => {
43        $crate::unsafe_precondition_assert!(@inner $cond, ::core::stringify!($cond))
44    };
45
46    ($cond:expr, $($arg:tt)+) => {
47        $crate::unsafe_precondition_assert!(@inner $cond, $crate::prelude::fmt!($($arg)+))
48    };
49
50    (@inner $cond:expr, $msg:expr) => {
51        ::core::debug_assert!($cond, "unsafe precondition violated: {}", $msg)
52    };
53}