Skip to content

Commit d6e1999

Browse files
authored
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.
1 parent 38fd42a commit d6e1999

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

src/bytes_mut.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,10 @@ impl BytesMut {
670670

671671
// Compare the condition in the `kind == KIND_VEC` case above
672672
// for more details.
673-
if v_capacity >= new_cap && offset >= len {
673+
if v_capacity >= new_cap + offset {
674+
self.cap = new_cap;
675+
// no copy is necessary
676+
} else if v_capacity >= new_cap && offset >= len {
674677
// The capacity is sufficient, and copying is not too much
675678
// overhead: reclaim the buffer!
676679

tests/test_bytes.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,34 @@ fn reserve_in_arc_unique_doubles() {
515515
assert_eq!(2000, bytes.capacity());
516516
}
517517

518+
#[test]
519+
fn reserve_in_arc_unique_does_not_overallocate_after_split() {
520+
let mut bytes = BytesMut::from(LONG);
521+
let orig_capacity = bytes.capacity();
522+
drop(bytes.split_off(LONG.len() / 2));
523+
524+
// now bytes is Arc and refcount == 1
525+
526+
let new_capacity = bytes.capacity();
527+
bytes.reserve(orig_capacity - new_capacity);
528+
assert_eq!(bytes.capacity(), orig_capacity);
529+
}
530+
531+
#[test]
532+
fn reserve_in_arc_unique_does_not_overallocate_after_multiple_splits() {
533+
let mut bytes = BytesMut::from(LONG);
534+
let orig_capacity = bytes.capacity();
535+
for _ in 0..10 {
536+
drop(bytes.split_off(LONG.len() / 2));
537+
538+
// now bytes is Arc and refcount == 1
539+
540+
let new_capacity = bytes.capacity();
541+
bytes.reserve(orig_capacity - new_capacity);
542+
}
543+
assert_eq!(bytes.capacity(), orig_capacity);
544+
}
545+
518546
#[test]
519547
fn reserve_in_arc_nonunique_does_not_overallocate() {
520548
let mut bytes = BytesMut::with_capacity(1000);

0 commit comments

Comments
 (0)