Fix overflow bug in `Weight` constructors
What changed, and why it matters
This commit fixes a panic (crash) in two Bitcoin weight-unit conversion helpers when they are called on the maximum possible weight value. The functions now use saturating addition, so instead of overflowing and crashing they return a large but valid rounded-up result. This is a reliability fix that prevents denial-of-service-style crashes from untrusted inputs.
Review callers of `to_kwu_ceil()` and `to_vbytes_ceil()` to confirm they do not rely on overflow/panic behavior, and include this fix in the next maintenance release. No immediate incident response is required unless an application exposes these helpers to adversarial input.
Security signals we found
Integer overflow in public conversion API
Potential panic on untrusted/malicious max-value weight input
Denial-of-service vector via crafted `Weight::MAX` usage
Use of `saturating_add` to eliminate overflow panic
Evidence from the diff
The patch changes Weight::to_kwu_ceil() and Weight::to_vbytes_ceil() in units/src/weight.rs from plain + to u64::saturating_add(...). Previously, calling either method on Weight::MAX (a u64::MAX inner value) caused an arithmetic overflow panic in debug builds or unexpected wrapping behavior. The fix ensures the addition saturates at u64::MAX, and the subsequent integer division yields a well-defined ceiling value. Tests for Weight::MAX are added for both methods.
Changed components
units/src/weight.rsWeight::to_kwu_ceil()Weight::to_vbytes_ceil()Inspect captured patch +4 / −2
diff --git a/units/src/weight.rs b/units/src/weight.rs
index 5c457f17..7a01332a 100644
--- a/units/src/weight.rs
+++ b/units/src/weight.rs
@@ -105,14 +105,14 @@ impl Weight {
pub const fn to_kwu_floor(self) -> u64 { self.to_wu() / 1000 }
/// Converts to kilo weight units rounding up.
- pub const fn to_kwu_ceil(self) -> u64 { (self.to_wu() + 999) / 1000 }
+ pub const fn to_kwu_ceil(self) -> u64 { self.to_wu().saturating_add(999) / 1000 }
/// Converts to vB rounding down.
pub const fn to_vbytes_floor(self) -> u64 { self.to_wu() / Self::WITNESS_SCALE_FACTOR }
/// Converts to vB rounding up.
pub const fn to_vbytes_ceil(self) -> u64 {
- (self.to_wu() + Self::WITNESS_SCALE_FACTOR - 1) / Self::WITNESS_SCALE_FACTOR
+ self.to_wu().saturating_add(Self::WITNESS_SCALE_FACTOR - 1) / Self::WITNESS_SCALE_FACTOR
}
/// Checked addition.
@@ -387,6 +387,7 @@ mod tests {
fn to_kwu_ceil() {
assert_eq!(Weight::from_wu(1_000).to_kwu_ceil(), 1);
assert_eq!(Weight::from_wu(1_001).to_kwu_ceil(), 2);
+ assert_eq!(Weight::MAX.to_kwu_ceil(), u64::MAX / 1_000);
}
#[test]
@@ -399,6 +400,7 @@ mod tests {
fn to_vb_ceil() {
assert_eq!(Weight::from_wu(4).to_vbytes_ceil(), 1);
assert_eq!(Weight::from_wu(5).to_vbytes_ceil(), 2);
+ assert_eq!(Weight::MAX.to_vbytes_ceil(), u64::MAX / Weight::WITNESS_SCALE_FACTOR);
}
#[test]
Why this scored 38/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.