[PATCH v4] rust: num: restrict bool conversion to unsigned Bounded
Younes Akhouayri <[email protected]>
| Newsgroups | org.kernel.feeds.b4-sent,org.kernel.vger.linux-kernel,org.kernel.vger.rust-for-linux,org.kernel.vger.stable |
|---|---|
| Message-ID | <20260822-fix-rust-bounded-from-bool-submit-v4-1-aa780bfe7f30@younes.io> |
From<bool> turns true into 1. A signed Bounded with N = 1 can hold
only -1 and 0. The current implementation can therefore create a value
that breaks Bounded's invariant. Deref relies on that invariant and
calls unreachable_unchecked() when it is broken, so safe Rust can reach
undefined behavior.
The other primitive conversions require the source and destination to
have the same signedness. Treat bool as an unsigned one-bit value and
allow conversions between bool and Bounded only when the backing integer
type is unsigned.
Fixes: 01e345e82ec3 ("rust: num: add Bounded integer wrapping type")
Closes: https://lore.kernel.org/rust-for-linux/[email protected]/
Cc: [email protected]
Suggested-by: Alexandre Courbot <[email protected]>
Assisted-by: Codex:gpt-5.6-sol
Signed-off-by: Younes Akhouayri <[email protected]>
---
Only allow conversions between bool and unsigned Bounded types.
---
Changes in v4:
- Restrict Bounded-to-bool conversion and into_bool() to unsigned types.
- Link to v3: https://patch.msgid.link/20260815-fix-rust-bounded-from-bool-submit-v3-1-fdca23008397@younes.io
Changes in v3:
- Restrict From<bool> to unsigned Bounded types, matching the other
primitive conversions.
- Remove the BoolFits helper and signed-width list.
- Link to v2: https://lore.kernel.org/rust-for-linux/20260815-fix-rust-bounded-from-bool-submit-v2-1-aa35bb2c22d1@younes.io/
Changes in v2:
- Use vertical formatting for the nested `num` import.
- Link to v1: https://lore.kernel.org/rust-for-linux/20260815-fix-rust-bounded-from-bool-submit-v1-1-882227bf40ba@younes.io/
To: Alexandre Courbot <[email protected]>
To: Yury Norov <[email protected]>
To: Miguel Ojeda <[email protected]>
To: Boqun Feng <[email protected]>
To: Gary Guo <[email protected]>
To: Björn Roy Baron <[email protected]>
To: Benno Lossin <[email protected]>
To: Andreas Hindborg <[email protected]>
To: Alice Ryhl <[email protected]>
To: Trevor Gross <[email protected]>
To: Danilo Krummrich <[email protected]>
To: Daniel Almeida <[email protected]>
To: Tamir Duberstein <[email protected]>
To: Onur Özkan <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
rust/kernel/num/bounded.rs | 30 +++++++++++++++++++++---------
1 file changed, 21 insertions(+), 9 deletions(-)
diff --git a/rust/kernel/num/bounded.rs b/rust/kernel/num/bounded.rs
index d192610a687d..2a2b0a4bca5e 100644
--- a/rust/kernel/num/bounded.rs
+++ b/rust/kernel/num/bounded.rs
@@ -13,7 +13,10 @@
};
use kernel::{
- num::Integer,
+ num::{
+ Integer,
+ Unsigned, //
+ },
prelude::*, //
};
@@ -174,13 +177,16 @@ 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 `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);
+///
+/// // This does not build because `i8` is signed.
+/// // let _ = Bounded::<i8, 2>::from(true);
/// ```
///
/// Infallible conversions from a [`Bounded`] to a primitive integer are also supported, and
@@ -203,12 +209,16 @@ fn fits_within<T: Integer>(value: T, num_bits: u32) -> bool {
/// let _v = Bounded::<u32, 10>::new::<10>();
/// // assert_eq!(u8::from(_v), 10);
///
-/// // Single-bit `Bounded`s can be converted into a boolean.
+/// // Unsigned single-bit `Bounded`s can be converted into a boolean.
/// let v = Bounded::<u8, 1>::new::<1>();
/// assert_eq!(bool::from(v), true);
///
/// let v = Bounded::<u8, 1>::new::<0>();
/// assert_eq!(bool::from(v), false);
+///
+/// // This does not build because `i8` is signed.
+/// // let v = Bounded::<i8, 1>::new::<-1>();
+/// // let _ = bool::from(v);
/// ```
///
/// Fallible conversions from any primitive integer to any [`Bounded`] are also supported using the
@@ -1109,31 +1119,33 @@ fn from(value: Bounded<T, N>) -> $type {
i8 i16 i32 i64 isize
);
-// Single-bit `Bounded`s can be converted from/to a boolean.
+// Unsigned single-bit `Bounded`s can be converted to a boolean.
impl<T> From<Bounded<T, 1>> for bool
where
- T: Integer + Zeroable,
+ T: Integer<Signedness = Unsigned> + Zeroable,
{
fn from(value: Bounded<T, 1>) -> Self {
value.get() != Zeroable::zeroed()
}
}
+// Booleans can be converted to unsigned `Bounded`s.
+
impl<T, const N: u32> From<bool> for Bounded<T, N>
where
- T: Integer + From<bool>,
+ T: Integer<Signedness = Unsigned> + From<bool>,
{
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: A boolean is represented by `0` or `1`, so it fits within any valid unsigned
+ // `Bounded` width.
unsafe { Self::__new(T::from(value)) }
}
}
impl<T> Bounded<T, 1>
where
- T: Integer + Zeroable,
+ T: Integer<Signedness = Unsigned> + Zeroable,
{
/// Converts this [`Bounded`] into a [`bool`].
///
---
base-commit: 47f27155f17498fccb1f222f79089642337498a9
change-id: 20260815-fix-rust-bounded-from-bool-submit-3af836d8f718
Best regards,
--
Younes Akhouayri <[email protected]>