Fix reserve over allocating underlying buffer (#560)

Fixes calls to `reserve` when the underlying shared buffer was already
big enough to fit the requested capacity. Previously a new even larger
buffer was created anyways. This could eventually lead to an OOM
condition.
This commit is contained in:
Matt Schulte
2022-07-30 11:16:32 +02:00
committed by GitHub
parent 38fd42acba
commit d6e1999d97
2 changed files with 32 additions and 1 deletions
+4 -1
View File
@@ -670,7 +670,10 @@ impl BytesMut {
// Compare the condition in the `kind == KIND_VEC` case above
// for more details.
if v_capacity >= new_cap && offset >= len {
if v_capacity >= new_cap + offset {
self.cap = new_cap;
// no copy is necessary
} else if v_capacity >= new_cap && offset >= len {
// The capacity is sufficient, and copying is not too much
// overhead: reclaim the buffer!
+28
View File
@@ -515,6 +515,34 @@ fn reserve_in_arc_unique_doubles() {
assert_eq!(2000, bytes.capacity());
}
#[test]
fn reserve_in_arc_unique_does_not_overallocate_after_split() {
let mut bytes = BytesMut::from(LONG);
let orig_capacity = bytes.capacity();
drop(bytes.split_off(LONG.len() / 2));
// now bytes is Arc and refcount == 1
let new_capacity = bytes.capacity();
bytes.reserve(orig_capacity - new_capacity);
assert_eq!(bytes.capacity(), orig_capacity);
}
#[test]
fn reserve_in_arc_unique_does_not_overallocate_after_multiple_splits() {
let mut bytes = BytesMut::from(LONG);
let orig_capacity = bytes.capacity();
for _ in 0..10 {
drop(bytes.split_off(LONG.len() / 2));
// now bytes is Arc and refcount == 1
let new_capacity = bytes.capacity();
bytes.reserve(orig_capacity - new_capacity);
}
assert_eq!(bytes.capacity(), orig_capacity);
}
#[test]
fn reserve_in_arc_nonunique_does_not_overallocate() {
let mut bytes = BytesMut::with_capacity(1000);