Skip to content

Commit 68845bd

Browse files
authored
fix: HeaderMap::reserve allocates insufficient capacity (#741)
This bug caused additional allocation when attempted to insert the requested number of entries. This commit fix that by converting capacity to raw capacity before allocation.
1 parent 4e02046 commit 68845bd

File tree

2 files changed

+33
-7
lines changed

2 files changed

+33
-7
lines changed

src/header/map.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -707,20 +707,22 @@ impl<T> HeaderMap<T> {
707707
.checked_add(additional)
708708
.ok_or_else(MaxSizeReached::new)?;
709709

710-
if cap > self.indices.len() {
711-
let cap = cap
710+
let raw_cap = to_raw_capacity(cap);
711+
712+
if raw_cap > self.indices.len() {
713+
let raw_cap = raw_cap
712714
.checked_next_power_of_two()
713715
.ok_or_else(MaxSizeReached::new)?;
714-
if cap > MAX_SIZE {
716+
if raw_cap > MAX_SIZE {
715717
return Err(MaxSizeReached::new());
716718
}
717719

718720
if self.entries.is_empty() {
719-
self.mask = cap as Size - 1;
720-
self.indices = vec![Pos::none(); cap].into_boxed_slice();
721-
self.entries = Vec::with_capacity(usable_capacity(cap));
721+
self.mask = raw_cap as Size - 1;
722+
self.indices = vec![Pos::none(); raw_cap].into_boxed_slice();
723+
self.entries = Vec::with_capacity(usable_capacity(raw_cap));
722724
} else {
723-
self.try_grow(cap)?;
725+
self.try_grow(raw_cap)?;
724726
}
725727
}
726728

tests/header_map.rs

+24
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,30 @@ fn reserve_overflow() {
6363
headers.reserve(std::usize::MAX); // next_power_of_two overflows
6464
}
6565

66+
#[test]
67+
fn reserve() {
68+
let mut headers = HeaderMap::<usize>::default();
69+
assert_eq!(headers.capacity(), 0);
70+
71+
let requested_cap = 8;
72+
headers.reserve(requested_cap);
73+
74+
let reserved_cap = headers.capacity();
75+
assert!(
76+
reserved_cap >= requested_cap,
77+
"requested {} capacity, but it reserved only {} entries",
78+
requested_cap,
79+
reserved_cap,
80+
);
81+
82+
for i in 0..requested_cap {
83+
let name = format!("h{i}").parse::<HeaderName>().unwrap();
84+
headers.insert(name, i);
85+
}
86+
87+
assert_eq!(headers.capacity(), reserved_cap, "unexpected reallocation");
88+
}
89+
6690
#[test]
6791
fn drain() {
6892
let mut headers = HeaderMap::new();

0 commit comments

Comments
 (0)