Skip to content

Commit d0293b0

Browse files
authored
Merge commit from fork
* Add repro for integer overflow Signed-off-by: Alice Ryhl <aliceryhl@google.com> * Always check overflow in new_cap + offset Signed-off-by: Alice Ryhl <aliceryhl@google.com> --------- Signed-off-by: Alice Ryhl <aliceryhl@google.com>
1 parent a7952fb commit d0293b0

File tree

3 files changed

+28
-8
lines changed

3 files changed

+28
-8
lines changed

ci/miri.sh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,6 @@ export MIRIFLAGS="-Zmiri-strict-provenance"
88

99
cargo miri test
1010
cargo miri test --target mips64-unknown-linux-gnuabi64
11+
12+
# run with wrapping integer overflow instead of panic
13+
cargo miri test --release

src/bytes_mut.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -695,9 +695,15 @@ impl BytesMut {
695695

696696
let offset = self.ptr.as_ptr().offset_from(ptr) as usize;
697697

698+
let new_cap_plus_offset = match new_cap.checked_add(offset) {
699+
Some(new_cap_plus_offset) => new_cap_plus_offset,
700+
None if !allocate => return false,
701+
None => panic!("overflow"),
702+
};
703+
698704
// Compare the condition in the `kind == KIND_VEC` case above
699705
// for more details.
700-
if v_capacity >= new_cap + offset {
706+
if v_capacity >= new_cap_plus_offset {
701707
self.cap = new_cap;
702708
// no copy is necessary
703709
} else if v_capacity >= new_cap && offset >= len {
@@ -713,14 +719,12 @@ impl BytesMut {
713719
if !allocate {
714720
return false;
715721
}
716-
// calculate offset
717-
let off = (self.ptr.as_ptr() as usize) - (v.as_ptr() as usize);
718722

719723
// new_cap is calculated in terms of `BytesMut`, not the underlying
720724
// `Vec`, so it does not take the offset into account.
721725
//
722726
// Thus we have to manually add it here.
723-
new_cap = new_cap.checked_add(off).expect("overflow");
727+
new_cap = new_cap_plus_offset;
724728

725729
// The vector capacity is not sufficient. The reserve request is
726730
// asking for more than the initial buffer capacity. Allocate more
@@ -742,13 +746,13 @@ impl BytesMut {
742746
// the unused capacity of the vector is copied over to the new
743747
// allocation, so we need to ensure that we don't have any data we
744748
// care about in the unused capacity before calling `reserve`.
745-
debug_assert!(off + len <= v.capacity());
746-
v.set_len(off + len);
749+
debug_assert!(offset + len <= v.capacity());
750+
v.set_len(offset + len);
747751
v.reserve(new_cap - v.len());
748752

749753
// Update the info
750-
self.ptr = vptr(v.as_mut_ptr().add(off));
751-
self.cap = v.capacity() - off;
754+
self.ptr = vptr(v.as_mut_ptr().add(offset));
755+
self.cap = v.capacity() - offset;
752756
}
753757

754758
return true;

tests/test_bytes.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1707,3 +1707,16 @@ fn bytes_mut_put_bytes_specialization() {
17071707
// If allocation is reused, capacity should be equal to original vec capacity.
17081708
assert_eq!(bytes_mut.capacity(), capacity);
17091709
}
1710+
1711+
#[test]
1712+
#[should_panic]
1713+
fn bytes_mut_reserve_overflow() {
1714+
let mut a = BytesMut::from(&b"hello world"[..]);
1715+
let mut b = a.split_off(5);
1716+
// Ensure b becomes the unique owner of the backing storage
1717+
drop(a);
1718+
// Trigger overflow in new_cap + offset inside reserve
1719+
b.reserve(usize::MAX - 6);
1720+
// This call relies on the corrupted cap and may cause UB & HBO
1721+
b.put_u8(b'h');
1722+
}

0 commit comments

Comments
 (0)