From nobody Fri Sep 25 22:19:31 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EDAD525C818; Tue, 8 Sep 2026 04:40:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788842433; cv=none; b=cjvizquNBjNRtiizXhVKGLX9/Y1E56eNjwCovSRnI3sKaCfsnj+dXuXdNfk7mHirLw1/g7JrkKs72pOdiTdKn7r8WPjDfSa21nUiA9gsY3hbFvG6eTGeZXLnHsf4Vt64GS/DvtkUhCzUSxZy866KlPoRvtiuZpBBDOb4wPUuTOw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788842433; c=relaxed/simple; bh=uqWZN4R2OQIxsNEBMPRafa6W6zRwfZek/mynQtOCEA4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc; b=nihA8MhjQLmJEDNZsOgCHFStSmgyI7IaG1A4QXke2CZLIFzM41f9UGZDY8vPm0Qchs9ZPK+9hzmqxttO6QHd+kET/LkErRQ5Ug6pHbFi/G27XjIATu+80Q2tA+x3IkCYh1E8GWp4lar6V6nHrerIsBlg+iESJxzk85iFfySv0x0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=LCsyh3mR; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="LCsyh3mR" Received: by smtp.kernel.org (Postfix) with ESMTPS id 7992BC2BCB8; Tue, 8 Sep 2026 04:40:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1788842432; bh=uqWZN4R2OQIxsNEBMPRafa6W6zRwfZek/mynQtOCEA4=; h=From:Date:Subject:To:Cc:Reply-To:From; b=LCsyh3mR1hfDAOjU1WMB7FEjgS++EamQ0Y74HnY/nzYSU72c0foU4ioCj92PnjKD6 q+DLWrcz4VDGxWct9sC/uaguSOmzn6sxaCrSn8KGfTE5G9yf6eohG+2CktwQKoRPsJ oVm0eTYLkMxV+i6aukfrC6VHgnnayLRmoiNYJyPfVoP/WM9BIMtd2lGWKbPt3uBCNo LIkwC/vubO3nRoQCI2F08q9mTBZW4Tn1gqqc4aPi6osLs9v9/z+IwuJqEALANQoXou 7ogVm6KUFiB4fciq3KVh+MG3xUJualjUnHiOaY5M4kBbG0cRjMbU/uXkIP/xdSE+GD YulI/wF/JZ7xQ== Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id 534F4C79F9E; Tue, 8 Sep 2026 04:40:32 +0000 (UTC) From: Younes Akhouayri via B4 Relay Date: Tue, 08 Sep 2026 06:39:59 +0200 Subject: [PATCH v2] rust: num: document why Integer is sealed Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260908-docs-rust-num-integer-sealing-safety-v2-1-e8c65234db82@younes.io> X-B4-Tracking: v=1; b=H4sIAAAAAAAC/5WOTQ6CMBCFr2K6drQUBerKexgWpQwwRlvTKURCu Lv8nMDlN3nzvTcJxkDI4naYRMCBmLxbQB0PwnbGtQhULyyUVJnUMoPaW4bQcwTXv4FcxBYDMJo XuRbYNBhHSI1EpbPc6EshFtUnYEPfreZR7sx99UQbV/eaqAwjVME4260nH6gld9569s8l0xFHH 8Zt65Csrj9nDQkkkBfymqc6SaWy99H3DvlEXpTzPP8ACs769g4BAAA= X-Change-ID: 20260906-docs-rust-num-integer-sealing-safety-3a0e2967a948 To: Alexandre Courbot , Yury Norov , Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Daniel Almeida , Tamir Duberstein , =?utf-8?q?Onur_=C3=96zkan?= Cc: rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Younes Akhouayri X-Mailer: b4 0.15.2 X-Developer-Signature: v=1; a=ed25519-sha256; t=1788842431; l=9303; i=git@younes.io; s=20260712; h=from:subject:message-id; bh=Npbz8G8u3MVnEdlz8DnebUk4PDv4U212b+94+h5OrC8=; b=YiE7+5KB3cJuv28DOLy2HKRm0h7SC4WELGqi/f/u/IiYFHrwmNsGWOFhSzEjq1n8TmG+2JXrK u5Pzyk1ks7LB0ZGHUXoNxR29fIMrlQfGXlEQit9qNh6zGQqiCpfox7b X-Developer-Key: i=git@younes.io; a=ed25519; pk=1DRfzPrQ04RQHHgGK28t+vjIAPv5oISPiAdLMU6J5dE= X-Endpoint-Received: by B4 Relay for git@younes.io/20260712 with auth_id=866 X-Original-From: Younes Akhouayri Reply-To: git@younes.io From: Younes Akhouayri Bounded relies on Integer implementations to provide primitive integer semantics. Unsafe blocks use those semantics to justify unchecked construction and conversion, but their safety comments do not say why a safe trait may be trusted. Document the seal at those safety comments and next to the private supertrait. Suggested-by: Miguel Ojeda Suggested-by: Gary Guo Link: https://lore.kernel.org/all/CANiq72m8kycbfQ1teyne-OtB5d5TsUcX_WW0FCkW= B3Ayyg-qWw@mail.gmail.com/ Link: https://lore.kernel.org/all/DL88SQWYU15W.2CVZB5NVSSJGK@garyguo.net/ Link: https://lore.kernel.org/all/CANiq72kx-YPPEruOFdu-Dp7GX+8=3DEt6svG+sQt= qEmmF7kpnVyQ@mail.gmail.com/ Signed-off-by: Younes Akhouayri --- Changes in v2: - Shorten the comment explaining why `Integer` is sealed. - Mention the seal in the `SAFETY` comments that rely on it. - Link to v1: https://patch.msgid.link/20260906-docs-rust-num-integer-seali= ng-safety-v1-1-78057391302c@younes.io To: Alexandre Courbot To: Yury Norov To: Miguel Ojeda To: Boqun Feng To: Gary Guo To: Bj=C3=B6rn Roy Baron To: Benno Lossin To: Andreas Hindborg To: Alice Ryhl To: Trevor Gross To: Danilo Krummrich To: Daniel Almeida To: Tamir Duberstein To: Onur =C3=96zkan Cc: rust-for-linux@vger.kernel.org Cc: linux-kernel@vger.kernel.org --- rust/kernel/num.rs | 1 + rust/kernel/num/bounded.rs | 48 ++++++++++++++++++++++++++----------------= ---- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/rust/kernel/num.rs b/rust/kernel/num.rs index de589792a77a..0449e84a384a 100644 --- a/rust/kernel/num.rs +++ b/rust/kernel/num.rs @@ -21,6 +21,7 @@ pub trait Sealed {} =20 /// Describes core properties of integer types. pub trait Integer: + // Sealed so that unsafe code can rely on the correctness of its imple= mentations. private::Sealed + Sized + Copy diff --git a/rust/kernel/num/bounded.rs b/rust/kernel/num/bounded.rs index 2a2b0a4bca5e..1a3f369cd886 100644 --- a/rust/kernel/num/bounded.rs +++ b/rust/kernel/num/bounded.rs @@ -336,7 +336,8 @@ impl Bounded /// ``` pub fn try_new(value: T) -> Option { fits_within(value, N).then(|| { - // SAFETY: `fits_within` confirmed that `value` can be represe= nted within `N` bits. + // SAFETY: `Integer` is sealed, so `fits_within` has primitive= integer semantics and + // confirmed that `value` can be represented within `N` bits. unsafe { Self::__new(value) } }) } @@ -379,7 +380,8 @@ pub fn from_expr(expr: T) -> Self { "Requested value larger than maximal representable value." ); =20 - // SAFETY: `fits_within` confirmed that `expr` can be represented = within `N` bits. + // SAFETY: `Integer` is sealed, so `fits_within` has primitive int= eger semantics and + // confirmed that `expr` can be represented within `N` bits. unsafe { Self::__new(expr) } } =20 @@ -420,8 +422,8 @@ pub const fn extend(self) -> Bounded { "Requested number of bits is less than the current representat= ion." ); =20 - // SAFETY: The value did fit within `N` bits, so it will all the m= ore fit within - // the larger `M` bits. + // SAFETY: `Integer` is sealed, so the `Bounded` invariant can be = relied upon. The value + // did fit within `N` bits, so it will all the more fit within the= larger `M` bits. unsafe { Bounded::__new(self.0) } } =20 @@ -472,12 +474,13 @@ pub fn cast(self) -> Bounded T: Integer, U: Integer, { - // SAFETY: The converted value is represented using `N` bits, `U` = can contain `N` bits, and - // `U` and `T` have the same sign, hence this conversion cannot fa= il. + // SAFETY: `Integer` is sealed, so the bit widths and signedness a= re correct. The converted + // value is represented using `N` bits, `U` can contain `N` bits, = and `U` and `T` have the + // same sign, hence this conversion cannot fail. let value =3D unsafe { U::try_from(self.get()).unwrap_unchecked() = }; =20 - // SAFETY: Although the backing type has changed, the value is sti= ll represented within - // `N` bits, and with the same signedness. + // SAFETY: `Integer` is sealed, so the signedness is correct. Alth= ough the backing type has + // changed, the value is still represented within `N` bits, and wi= th the same signedness. unsafe { Bounded::__new(value) } } =20 @@ -498,8 +501,9 @@ pub fn shr(self) -> B= ounded { const_assert!(SHIFT < T::BITS); const_assert!(RES + SHIFT >=3D N); =20 - // SAFETY: We shift the value right by `SHIFT`, reducing the numbe= r of bits needed to - // represent the shifted value by as much, and just asserted that = `RES >=3D N - SHIFT`. + // SAFETY: `Integer` is sealed, so the shift has primitive integer= semantics. We reduce the + // number of bits needed to represent the shifted value by `SHIFT`= , and just asserted that + // `RES >=3D N - SHIFT`. unsafe { Bounded::__new(self.0 >> SHIFT) } } =20 @@ -550,8 +554,9 @@ pub fn shr_exact(self= ) -> Option(self) -> Bounded { const_assert!(RES >=3D N + SHIFT); =20 - // SAFETY: We shift the value left by `SHIFT`, augmenting the numb= er of bits needed to - // represent the shifted value by as much, and just asserted that = `RES >=3D N + SHIFT`. + // SAFETY: `Integer` is sealed, so the shift has primitive integer= semantics. We augment + // the number of bits needed to represent the shifted value by `SH= IFT`, and just asserted + // that `RES >=3D N + SHIFT`. unsafe { Bounded::__new(self.0 << SHIFT) } } } @@ -565,8 +570,8 @@ impl Deref for Bounded fn deref(&self) -> &Self::Target { // Enforce the invariant to inform the compiler of the bounds of t= he value. if !fits_within(self.0, N) { - // SAFETY: Per the `Bounded` invariants, `fits_within` can nev= er return `false` on the - // value of a valid instance. + // SAFETY: `Integer` is sealed, so `fits_within` has primitive= integer semantics. Per + // the `Bounded` invariants, it cannot return `false` on the v= alue of a valid instance. unsafe { core::hint::unreachable_unchecked() } } =20 @@ -1028,8 +1033,9 @@ impl From<$type> for Bounded Self: AtLeastXBits<{ <$type as Integer>::BITS as usize }>, { fn from(value: $type) -> Self { - // SAFETY: The trait bound on `Self` guarantees that `N` b= its is - // enough to hold any value of the source type. + // SAFETY: `Integer` is sealed, so the bit widths and sign= edness are correct. The + // trait bound on `Self` guarantees that `N` bits is enoug= h to hold any value of + // the source type. unsafe { Self::__new(T::from(value)) } } } @@ -1104,9 +1110,9 @@ impl From> for $type Bounded: FitsInXBits<{ <$type as Integer>::BITS as usize= }>, { fn from(value: Bounded) -> $type { - // SAFETY: The trait bound on `Bounded` ensures that any v= alue it holds (which - // is constrained to `N` bits) can fit into the destinatio= n type, so this - // conversion cannot fail. + // SAFETY: `Integer` is sealed, so the bit widths and sign= edness are correct. The + // trait bound on `Bounded` ensures that any value it hold= s (which is constrained + // to `N` bits) can fit into the destination type, so this= conversion cannot fail. unsafe { <$type>::try_from(value.get()).unwrap_unchecked()= } } } @@ -1137,8 +1143,8 @@ impl From for Bounded T: Integer + From, { fn from(value: bool) -> Self { - // SAFETY: A boolean is represented by `0` or `1`, so it fits with= in any valid unsigned - // `Bounded` width. + // SAFETY: `Integer` is sealed, so `T` is a primitive unsigned int= eger. A boolean is + // represented by `0` or `1`, so it fits within any valid unsigned= `Bounded` width. unsafe { Self::__new(T::from(value)) } } } --- base-commit: c6709d5e14072d0e3d02f291daee46a199e5dad3 change-id: 20260906-docs-rust-num-integer-sealing-safety-3a0e2967a948 Best regards, -- =20 Younes Akhouayri