You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@opendal.apache.org by as...@apache.org on 2026/05/04 06:23:42 UTC
(opendal) branch main updated: fix(core): prevent integer overflow/underflow in BytesRange conversions (#7398)
This is an automated email from the ASF dual-hosted git repository.
asukaminato0721 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/opendal.git
The following commit(s) were added to refs/heads/main by this push:
new 2ac599f2f fix(core): prevent integer overflow/underflow in BytesRange conversions (#7398)
2ac599f2f is described below
commit 2ac599f2fe5fdbc1eca5ebd06964603f986f5974
Author: TennyZhuang <zt...@gmail.com>
AuthorDate: Mon May 4 14:23:36 2026 +0800
fix(core): prevent integer overflow/underflow in BytesRange conversions (#7398)
* fix(core): prevent integer overflow/underflow in BytesRange conversions
Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
* fix: rustfmt formatting
Co-Authored-By: Claude Opus 4.6 <no...@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <no...@anthropic.com>
---
core/core/src/raw/http_util/bytes_range.rs | 81 +++++++++++++++++++++++++++---
1 file changed, 74 insertions(+), 7 deletions(-)
diff --git a/core/core/src/raw/http_util/bytes_range.rs b/core/core/src/raw/http_util/bytes_range.rs
index 260dadfdf..b2b2f8ce0 100644
--- a/core/core/src/raw/http_util/bytes_range.rs
+++ b/core/core/src/raw/http_util/bytes_range.rs
@@ -75,10 +75,17 @@ impl BytesRange {
///
/// # Panics
///
- /// Panic if input `n` is larger than the size of the range.
+ /// Panic if advancing the offset would overflow or if input `n` is larger
+ /// than the size of the range.
pub fn advance(&mut self, n: u64) {
- self.0 += n;
- self.1 = self.1.map(|size| size - n);
+ self.0 = self
+ .0
+ .checked_add(n)
+ .expect("BytesRange::advance overflow: offset + n exceeds u64::MAX");
+ self.1 = self.1.map(|size| {
+ size.checked_sub(n)
+ .expect("BytesRange::advance underflow: n exceeds range size")
+ });
}
/// Check if this range is full of this content.
@@ -98,7 +105,11 @@ impl BytesRange {
(
Bound::Included(self.0),
match self.1 {
- Some(size) => Bound::Excluded(self.0 + size),
+ Some(size) => Bound::Excluded(
+ self.0
+ .checked_add(size)
+ .expect("BytesRange::to_range overflow: offset + size exceeds u64::MAX"),
+ ),
None => Bound::Unbounded,
},
)
@@ -106,10 +117,26 @@ impl BytesRange {
/// Convert bytes range into rust range with usize.
pub fn to_range_as_usize(self) -> impl RangeBounds<usize> {
+ let offset: usize = self
+ .0
+ .try_into()
+ .expect("BytesRange::to_range_as_usize: offset exceeds usize::MAX");
(
- Bound::Included(self.0 as usize),
+ Bound::Included(offset),
match self.1 {
- Some(size) => Bound::Excluded((self.0 + size) as usize),
+ Some(size) => {
+ let end: usize = self
+ .0
+ .checked_add(size)
+ .expect(
+ "BytesRange::to_range_as_usize overflow: offset + size exceeds u64::MAX",
+ )
+ .try_into()
+ .expect(
+ "BytesRange::to_range_as_usize: offset + size exceeds usize::MAX",
+ );
+ Bound::Excluded(end)
+ }
None => Bound::Unbounded,
},
)
@@ -122,7 +149,12 @@ impl Display for BytesRange {
None => write!(f, "{}-", self.0),
// A zero-size range can't be represented as a valid HTTP Range.
Some(0) => Err(std::fmt::Error),
- Some(size) => write!(f, "{}-{}", self.0, self.0 + size - 1),
+ Some(size) => write!(
+ f,
+ "{}-{}",
+ self.0,
+ self.0.checked_add(size - 1).ok_or(std::fmt::Error)?
+ ),
}
}
}
@@ -324,4 +356,39 @@ mod tests {
BytesRange::from((u64::MAX)..)
);
}
+
+ #[test]
+ fn test_bytes_range_display_overflow() {
+ // offset=u64::MAX, size=2 would overflow in Display (u64::MAX + 1)
+ let range = BytesRange::new(u64::MAX, Some(2));
+ assert!(std::fmt::write(&mut String::new(), format_args!("{}", range)).is_err());
+ }
+
+ #[test]
+ #[should_panic(expected = "BytesRange::to_range overflow")]
+ fn test_bytes_range_to_range_overflow() {
+ let range = BytesRange::new(u64::MAX, Some(1));
+ let _ = range.to_range();
+ }
+
+ #[test]
+ #[should_panic(expected = "BytesRange::to_range_as_usize")]
+ fn test_bytes_range_to_range_as_usize_overflow() {
+ let range = BytesRange::new(u64::MAX, Some(1));
+ let _ = range.to_range_as_usize();
+ }
+
+ #[test]
+ #[should_panic(expected = "BytesRange::advance overflow")]
+ fn test_bytes_range_advance_offset_overflow() {
+ let mut range = BytesRange::new(u64::MAX, None);
+ range.advance(1);
+ }
+
+ #[test]
+ #[should_panic(expected = "BytesRange::advance underflow")]
+ fn test_bytes_range_advance_size_underflow() {
+ let mut range = BytesRange::new(0, Some(1));
+ range.advance(2);
+ }
}