mirror of
https://github.com/tokio-rs/bytes.git
synced 2026-08-24 00:00:14 +02:00
Merge commit from fork
* Add repro for integer overflow Signed-off-by: Alice Ryhl <[email protected]> * Always check overflow in new_cap + offset Signed-off-by: Alice Ryhl <[email protected]> --------- Signed-off-by: Alice Ryhl <[email protected]>
This commit is contained in:
@@ -8,3 +8,6 @@ export MIRIFLAGS="-Zmiri-strict-provenance"
|
|||||||
|
|
||||||
cargo miri test
|
cargo miri test
|
||||||
cargo miri test --target mips64-unknown-linux-gnuabi64
|
cargo miri test --target mips64-unknown-linux-gnuabi64
|
||||||
|
|
||||||
|
# run with wrapping integer overflow instead of panic
|
||||||
|
cargo miri test --release
|
||||||
|
|||||||
+12
-8
@@ -695,9 +695,15 @@ impl BytesMut {
|
|||||||
|
|
||||||
let offset = self.ptr.as_ptr().offset_from(ptr) as usize;
|
let offset = self.ptr.as_ptr().offset_from(ptr) as usize;
|
||||||
|
|
||||||
|
let new_cap_plus_offset = match new_cap.checked_add(offset) {
|
||||||
|
Some(new_cap_plus_offset) => new_cap_plus_offset,
|
||||||
|
None if !allocate => return false,
|
||||||
|
None => panic!("overflow"),
|
||||||
|
};
|
||||||
|
|
||||||
// Compare the condition in the `kind == KIND_VEC` case above
|
// Compare the condition in the `kind == KIND_VEC` case above
|
||||||
// for more details.
|
// for more details.
|
||||||
if v_capacity >= new_cap + offset {
|
if v_capacity >= new_cap_plus_offset {
|
||||||
self.cap = new_cap;
|
self.cap = new_cap;
|
||||||
// no copy is necessary
|
// no copy is necessary
|
||||||
} else if v_capacity >= new_cap && offset >= len {
|
} else if v_capacity >= new_cap && offset >= len {
|
||||||
@@ -713,14 +719,12 @@ impl BytesMut {
|
|||||||
if !allocate {
|
if !allocate {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// calculate offset
|
|
||||||
let off = (self.ptr.as_ptr() as usize) - (v.as_ptr() as usize);
|
|
||||||
|
|
||||||
// new_cap is calculated in terms of `BytesMut`, not the underlying
|
// new_cap is calculated in terms of `BytesMut`, not the underlying
|
||||||
// `Vec`, so it does not take the offset into account.
|
// `Vec`, so it does not take the offset into account.
|
||||||
//
|
//
|
||||||
// Thus we have to manually add it here.
|
// Thus we have to manually add it here.
|
||||||
new_cap = new_cap.checked_add(off).expect("overflow");
|
new_cap = new_cap_plus_offset;
|
||||||
|
|
||||||
// The vector capacity is not sufficient. The reserve request is
|
// The vector capacity is not sufficient. The reserve request is
|
||||||
// asking for more than the initial buffer capacity. Allocate more
|
// asking for more than the initial buffer capacity. Allocate more
|
||||||
@@ -742,13 +746,13 @@ impl BytesMut {
|
|||||||
// the unused capacity of the vector is copied over to the new
|
// the unused capacity of the vector is copied over to the new
|
||||||
// allocation, so we need to ensure that we don't have any data we
|
// allocation, so we need to ensure that we don't have any data we
|
||||||
// care about in the unused capacity before calling `reserve`.
|
// care about in the unused capacity before calling `reserve`.
|
||||||
debug_assert!(off + len <= v.capacity());
|
debug_assert!(offset + len <= v.capacity());
|
||||||
v.set_len(off + len);
|
v.set_len(offset + len);
|
||||||
v.reserve(new_cap - v.len());
|
v.reserve(new_cap - v.len());
|
||||||
|
|
||||||
// Update the info
|
// Update the info
|
||||||
self.ptr = vptr(v.as_mut_ptr().add(off));
|
self.ptr = vptr(v.as_mut_ptr().add(offset));
|
||||||
self.cap = v.capacity() - off;
|
self.cap = v.capacity() - offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -1707,3 +1707,16 @@ fn bytes_mut_put_bytes_specialization() {
|
|||||||
// If allocation is reused, capacity should be equal to original vec capacity.
|
// If allocation is reused, capacity should be equal to original vec capacity.
|
||||||
assert_eq!(bytes_mut.capacity(), capacity);
|
assert_eq!(bytes_mut.capacity(), capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn bytes_mut_reserve_overflow() {
|
||||||
|
let mut a = BytesMut::from(&b"hello world"[..]);
|
||||||
|
let mut b = a.split_off(5);
|
||||||
|
// Ensure b becomes the unique owner of the backing storage
|
||||||
|
drop(a);
|
||||||
|
// Trigger overflow in new_cap + offset inside reserve
|
||||||
|
b.reserve(usize::MAX - 6);
|
||||||
|
// This call relies on the corrupted cap and may cause UB & HBO
|
||||||
|
b.put_u8(b'h');
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user