From nobody Fri Dec 19 19:14:18 2025 Received: from mail-pl1-f169.google.com (mail-pl1-f169.google.com [209.85.214.169]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 41AFC2BB1D for ; Thu, 4 Dec 2025 03:39:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.169 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764819575; cv=none; b=VUrnQA9jsBgEqJyBLNKC6uj/d+NdcRl7N/IfCwGPNmEVUupc+w2v23kaNSXyM3SFFA71/rGkGaFu4jk+QkJAsBQzv7E6GmcccBzybYA3CHI2U3kT1S3UYaYNytJjo/DoaBwuT3WYefTkuLmJqd9f/WMuBeTHs6RicveUd4SsHQU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764819575; c=relaxed/simple; bh=+ybGsYf0RBQnvmp00NouKd8iAMMDnOtZX6WTXbrq2Ic=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=FnspiJ3KkI0vgkBfTOjUVWEjDu07gtdDQMf7+cve4SNTef+xLjxW4oowjdKA2qw0qMqleWEd2lcdGJU1V45QtUbIHxnLsr8yh6tE5ncaxnzXXWwYR1JBvrQNApBeawymJvVyIwTXI4X1zkGG6h6y8aY+Riv0Tg5M+tlC8zFx9nw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=U5tH7CBA; arc=none smtp.client-ip=209.85.214.169 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="U5tH7CBA" Received: by mail-pl1-f169.google.com with SMTP id d9443c01a7336-2958db8ae4fso5056025ad.2 for ; Wed, 03 Dec 2025 19:39:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1764819573; x=1765424373; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=smF45H3fLH7PutWmWCdb2k238cJntwhvu4VjXij7QU4=; b=U5tH7CBAXuUrT5niC4fyYAofELAsqU7lMq4cCkCBicYRu1p/sl8shi74jH6ouM7FZ9 p8vBW/IB9vAoBAWaK9G639YdT7gFGenAi3RadsUmiBlrGRt8zIcct+uEfMxYitB0SO4F us3dBtWVZVIGkbQiP+JLihg00dnZ/Qf9mEBuD2aOG7Ljt8xthED4wTLrKLR1RC1CNomP prQ6SSAGhkvltGs5Zc7psZ2b4247/RLIKLk6YyUUZKlpx1jfcpfkyzhEkL8PycSSaEsN DBBm7GsCTPHo3BUeru0IMzg7eaXFaNU9GMWGadL0sBz5npMXayXe21CjDKdTewhriSMI loyA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1764819573; x=1765424373; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=smF45H3fLH7PutWmWCdb2k238cJntwhvu4VjXij7QU4=; b=FvCngJ+YhnQIMKe/iqy0wg+L2aFA6ESOjTI/pxDtemMzT1MUDtMr+r+R5CKAtaFTIb j4W72WrNuEVGHd2SDzHR+oG2L8jJDyLPeEzSoj9PehuB6G6UwuuQvJo/kuH1MCnwoozR 53YdLZ8lm6USiSvdTrc8SVch4wa8Yc5DcWHgaq7OmH+GFfRxlAavQrYoci4TYsY4UOlm YFFrpUY+8xcVJwcswU4R4e3U2Bcyv20YpVBYcTRXviuzk4QCDQARlspvov8eHkolXkXs k6L9WQCiE9AUEbi9aZc0kN+lFV51aYtv8nDBUSwzwovs8+tX8pZmU9mkc72zFgDLPb8w nMVg== X-Forwarded-Encrypted: i=1; AJvYcCURjngYjmlBn47vYgoJu53hRa0fo3Xkqw2HONqbrEB04uq89qCJWQSg2f0xKuCgl8RSonpGAIUczoiouL8=@vger.kernel.org X-Gm-Message-State: AOJu0Yz13DxZtRGqwqqcjJ0YGQDGxFY1+k/Sj0pczj5KHk0eE90Bso2L Fc/ylnr2zJgXQMkm/GjSpJxJl0UXcPNG/JXWqaWRFi3LVmP4k84Y42Xa X-Gm-Gg: ASbGncsjCbpE36VNAvMukBUlCKB8MjcM5s8QABfX9yqZ8oLQ/IQdusqQdidFQ9fk8Ak xBVwzxfiWFiQZgPZ7Pm0aV04uClUHcayiL3ope1atBVBSm2aCWKLBdzcENu1KOJPEThAdZm43pz nlcfDKnUTIunvfU5adRNJFL/zmlz2cXHbnOsd0HIwEVkWqkmc3InxooAOFHrqFgkqV7GmoiYMcR YljFwuBvxgEJ6DDywliqnel5XSELSHWeuzEIUHsVWecNI/kNpSRGwu1fl7n5s1orzx+S/QWuuQ7 syRl/WZnXsybEUHpMGjK1GDjwQegBVYvfvcbyHGejcTUDXR+lNgOHOFNMiT6pvq7KslMiprbhH2 j6RvA7HRqsDybYIGFGNOhBTHeX49XfDW7aaAwSDL+aavZOHq+1WY/aQ9uJCpVL2fU3VgfiwMV+Y KVusZAGLiXgg4zsQbcowAl0Vlrql4SN3ugcUQ= X-Google-Smtp-Source: AGHT+IEcITuVheRBjkWopaK77Fb+R3+oNTtSfEUsOQkBlkV058WKkMu3hDPDBFPZubIbL9lBUJsr2w== X-Received: by 2002:a17:90b:37c6:b0:340:d1b5:bfda with SMTP id 98e67ed59e1d1-349125c1912mr5112173a91.3.1764819573468; Wed, 03 Dec 2025 19:39:33 -0800 (PST) Received: from localhost.localdomain ([49.213.140.88]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-349129c44c0sm1922954a91.1.2025.12.03.19.39.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 03 Dec 2025 19:39:33 -0800 (PST) From: Hsiu Che Yu To: Alexandre Courbot Cc: Hsiu Che Yu , Miguel Ojeda , Yury Norov , Boqun Feng , Gary Guo , =?UTF-8?q?Bj=C3=B6rn=20Roy=20Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v3] rust: num: bounded: mark __new as unsafe Date: Thu, 4 Dec 2025 11:38:48 +0800 Message-ID: <20251204033849.23480-1-yu.whisper.personal@gmail.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The `Bounded::__new()` constructor relies on the caller to ensure the value can be represented within N bits. Failing to uphold this requirement breaks the type invariant. Mark it as unsafe and document this requirement in a Safety section to make the contract explicit. Update all call sites to use unsafe blocks and change their comments from `INVARIANT:` to `SAFETY:`, as they are now justifying unsafe operations rather than establishing type invariants. Fixes: 01e345e82ec3a ("rust: num: add Bounded integer wrapping type") Link: https://lore.kernel.org/all/aS1qC_ol2XEpZ44b@google.com/ Reported-by: Miguel Ojeda Closes: https://github.com/Rust-for-Linux/linux/issues/1211 Signed-off-by: Hsiu Che Yu Acked-by: Alexandre Courbot --- Changes in v3: - Add `Link:` tag (suggested by Alexandre Courbot) - Remove empty line before Signed-off-by Changes in v2: - Mark `Bounded::__new` as unsafe and add Safety documentation - Update all call sites with unsafe blocks and SAFETY comments Link to v2: https://lore.kernel.org/rust-for-linux/20251202032541.78497-1-y= u.whisper.personal@gmail.com/ Link to v1: https://lore.kernel.org/rust-for-linux/20251201062516.45495-1-y= u.whisper.personal@gmail.com/ --- rust/kernel/num/bounded.rs | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/rust/kernel/num/bounded.rs b/rust/kernel/num/bounded.rs index f870080af8ac..5838c84f8a53 100644 --- a/rust/kernel/num/bounded.rs +++ b/rust/kernel/num/bounded.rs @@ -259,9 +259,9 @@ pub const fn new() -> Self { assert!(fits_within!(VALUE, $type, N)); } =20 - // INVARIANT: `fits_within` confirmed that `VALUE` can be = represented within + // SAFETY: `fits_within` confirmed that `VALUE` can be rep= resented within // `N` bits. - Self::__new(VALUE) + unsafe { Self::__new(VALUE) } } } )* @@ -284,7 +284,11 @@ impl Bounded /// /// The caller remains responsible for checking, either statically or = dynamically, that `value` /// can be represented as a `T` using at most `N` bits. - const fn __new(value: T) -> Self { + /// + /// # Safety + /// + /// The caller must ensure that `value` can be represented within `N` = bits. + const unsafe fn __new(value: T) -> Self { // Enforce the type invariants. const { // `N` cannot be zero. @@ -328,8 +332,8 @@ const fn __new(value: T) -> Self { /// ``` pub fn try_new(value: T) -> Option { fits_within(value, N).then(|| { - // INVARIANT: `fits_within` confirmed that `value` can be repr= esented within `N` bits. - Self::__new(value) + // SAFETY: `fits_within` confirmed that `value` can be represe= nted within `N` bits. + unsafe { Self::__new(value) } }) } =20 @@ -370,8 +374,8 @@ pub fn from_expr(expr: T) -> Self { "Requested value larger than maximal representable value." ); =20 - // INVARIANT: `fits_within` confirmed that `expr` can be represent= ed within `N` bits. - Self::__new(expr) + // SAFETY: `fits_within` confirmed that `expr` can be represented = within `N` bits. + unsafe { Self::__new(expr) } } =20 /// Returns the wrapped value as the backing type. @@ -410,9 +414,9 @@ pub const fn extend(self) -> Bounded { ); } =20 - // INVARIANT: The value did fit within `N` bits, so it will all th= e more fit within + // SAFETY: The value did fit within `N` bits, so it will all the m= ore fit within // the larger `M` bits. - Bounded::__new(self.0) + unsafe { Bounded::__new(self.0) } } =20 /// Attempts to shrink the number of bits usable for `self`. @@ -466,9 +470,9 @@ pub fn cast(self) -> Bounded // `U` and `T` have the same sign, hence this conversion cannot fa= il. let value =3D unsafe { U::try_from(self.get()).unwrap_unchecked() = }; =20 - // INVARIANT: Although the backing type has changed, the value is = still represented within + // SAFETY: Although the backing type has changed, the value is sti= ll represented within // `N` bits, and with the same signedness. - Bounded::__new(value) + unsafe { Bounded::__new(value) } } } =20 @@ -944,9 +948,9 @@ impl From<$type> for Bounded Self: AtLeastXBits<{ <$type as Integer>::BITS as usize }>, { fn from(value: $type) -> Self { - // INVARIANT: The trait bound on `Self` guarantees that `N= ` bits is + // SAFETY: The trait bound on `Self` guarantees that `N` b= its is // enough to hold any value of the source type. - Self::__new(T::from(value)) + unsafe { Self::__new(T::from(value)) } } } )* @@ -1051,8 +1055,8 @@ impl From for Bounded T: Integer + From, { fn from(value: bool) -> Self { - // INVARIANT: A boolean can be represented using a single bit, and= thus fits within any + // SAFETY: A boolean can be represented using a single bit, and th= us fits within any // integer type for any `N` > 0. - Self::__new(T::from(value)) + unsafe { Self::__new(T::from(value)) } } } --=20 2.43.0