[PATCH] rust: num: reject bool conversion to signed one-bit Bounded
Younes Akhouayri <[email protected]>
| Newsgroups | org.kernel.feeds.b4-sent,org.kernel.vger.rust-for-linux,org.kernel.vger.stable |
|---|---|
| Message-ID | <20260815-fix-rust-bounded-from-bool-submit-v1-1-882227bf40ba@younes.io> |
From<bool> turns true into 1. A signed Bounded with N = 1 can hold
only -1 and 0. From<bool> therefore creates a value that the type does
not allow. Deref assumes the value is valid and calls
unreachable_unchecked() when it is not. Safe Rust can therefore reach
undefined behavior.
Rust cannot write N >= 2 directly in this From implementation. Add a
private BoolFits trait. It accepts every valid unsigned width and signed
widths from 2 through 128. The current Integer types do not use more
than 128 bits, so this keeps every valid conversion.
Fixes: 01e345e82ec3 ("rust: num: add Bounded integer wrapping type")
Closes: https://lore.kernel.org/rust-for-linux/[email protected]/
Cc: [email protected]
Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Younes Akhouayri <[email protected]>
---
Do not allow From<bool> for signed Bounded values with N = 1.
Keep it available for signed Bounded values with N >= 2.
---
rust/kernel/num/bounded.rs | 50 +++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 45 insertions(+), 5 deletions(-)
diff --git a/rust/kernel/num/bounded.rs b/rust/kernel/num/bounded.rs
index d192610a687d..1856fe6c9865 100644
--- a/rust/kernel/num/bounded.rs
+++ b/rust/kernel/num/bounded.rs
@@ -13,7 +13,7 @@
};
use kernel::{
- num::Integer,
+ num::{Integer, Signed, Unsigned},
prelude::*, //
};
@@ -174,13 +174,26 @@ fn fits_within<T: Integer>(value: T, num_bits: u32) -> bool {
/// // `u8` (regardless of the passed value).
/// // let _ = Bounded::<u32, 6>::from(10u8);
///
-/// // Booleans can be converted into single-bit `Bounded`s.
+/// // Booleans can be converted into unsigned single-bit `Bounded`s.
///
/// let v = Bounded::<u64, 1>::from(false);
/// assert_eq!(v.get(), 0);
///
/// let v = Bounded::<u64, 1>::from(true);
/// assert_eq!(v.get(), 1);
+///
+/// // Signed integers need at least two bits to represent both `0` and `1`.
+/// let v = Bounded::<i8, 2>::from(true);
+/// assert_eq!(v.get(), 1);
+/// ```
+///
+/// A signed single-bit [`Bounded`] cannot represent `1`, so converting a boolean into one does not
+/// build.
+///
+/// ```compile_fail,E0277
+/// use kernel::num::Bounded;
+///
+/// let _: Bounded<i8, 1> = true.into();
/// ```
///
/// Infallible conversions from a [`Bounded`] to a primitive integer are also supported, and
@@ -1109,7 +1122,33 @@ fn from(value: Bounded<T, N>) -> $type {
i8 i16 i32 i64 isize
);
-// Single-bit `Bounded`s can be converted from/to a boolean.
+// Conversions between `Bounded`s and booleans.
+
+/// Marker for signedness types for which a valid `N`-bit integer can represent a boolean.
+trait BoolFits<const N: u32> {}
+
+impl<const N: u32> BoolFits<N> for Unsigned {}
+
+macro_rules! impl_signed_bool_fits {
+ ($($num_bits:literal)*) => {
+ $(
+ impl BoolFits<$num_bits> for Signed {}
+ )*
+ };
+}
+
+// `N >= 2` cannot be expressed as a trait bound without `generic_const_exprs`, so enumerate every
+// width supported by the current `Integer` implementations.
+impl_signed_bool_fits!(
+ 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
+ 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
+ 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
+ 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
+ 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
+ 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
+ 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
+ 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
+);
impl<T> From<Bounded<T, 1>> for bool
where
@@ -1123,10 +1162,11 @@ fn from(value: Bounded<T, 1>) -> Self {
impl<T, const N: u32> From<bool> for Bounded<T, N>
where
T: Integer + From<bool>,
+ T::Signedness: BoolFits<N>,
{
fn from(value: bool) -> Self {
- // SAFETY: A boolean can be represented using a single bit, and thus fits within any
- // integer type for any `N` > 0.
+ // SAFETY: `__new` enforces that `N` is a valid width, and the `BoolFits` bound guarantees
+ // that the integer representation of `value` fits within any such `N`.
unsafe { Self::__new(T::from(value)) }
}
}
---
base-commit: 47f27155f17498fccb1f222f79089642337498a9
change-id: 20260815-fix-rust-bounded-from-bool-submit-3af836d8f718
Best regards,
--
Younes Akhouayri <[email protected]>