Skip to content

Commit 722df55

Browse files
authored
Fixes panic for remove_entry and remove_entry_mult (#449)
* add test case for OccupiedEntry::remove_entry_mult This is just a self contained test case, currently reproducing the panic of #446. * expand test cases for remove_entry_mult * add multiple remove_entry_mult call tests to show more issues * test repeated HeaderMap::remove for comparison * tests showing similar problem with remove_entry on extra values * fix remove_entry by moving remove_found after remove_all_extra_values * fix remove_entry_mult by eager collection of extras before remove_found In order to remove extra values prior to remove_found, we must collect them eagerly. Eager collection is based on: commit 8ffe094 Author: Sean McArthur <[email protected]> AuthorDate: Mon Nov 25 17:34:30 2019 -0800 Commit: Sean McArthur <[email protected]> CommitDate: Tue Nov 26 10:03:09 2019 -0800 Make ValueDrain eagerly collect its extra values ...which was reverted in 6c2b789. Closes #446
1 parent 43c6e84 commit 722df55

File tree

2 files changed

+277
-34
lines changed

2 files changed

+277
-34
lines changed

src/header/map.rs

+63-33
Original file line numberDiff line numberDiff line change
@@ -206,10 +206,8 @@ pub struct ValueIterMut<'a, T> {
206206
/// An drain iterator of all values associated with a single header name.
207207
#[derive(Debug)]
208208
pub struct ValueDrain<'a, T> {
209-
raw_links: RawLinks<T>,
210-
extra_values: *mut Vec<ExtraValue<T>>,
211209
first: Option<T>,
212-
next: Option<usize>,
210+
next: Option<::std::vec::IntoIter<T>>,
213211
lt: PhantomData<&'a mut HeaderMap<T>>,
214212
}
215213

@@ -1193,13 +1191,16 @@ impl<T> HeaderMap<T> {
11931191
}
11941192

11951193
let raw_links = self.raw_links();
1196-
let extra_values = &mut self.extra_values as *mut _;
1194+
let extra_values = &mut self.extra_values;
1195+
1196+
let next = links.map(|l| {
1197+
drain_all_extra_values(raw_links, extra_values, l.next)
1198+
.into_iter()
1199+
});
11971200

11981201
ValueDrain {
1199-
raw_links,
1200-
extra_values,
12011202
first: Some(old),
1202-
next: links.map(|l| l.next),
1203+
next: next,
12031204
lt: PhantomData,
12041205
}
12051206
}
@@ -1368,6 +1369,10 @@ impl<T> HeaderMap<T> {
13681369
}
13691370

13701371
/// Remove an entry from the map.
1372+
///
1373+
/// Warning: To avoid inconsistent state, extra values _must_ be removed
1374+
/// for the `found` index (via `remove_all_extra_values` or similar)
1375+
/// _before_ this method is called.
13711376
#[inline]
13721377
fn remove_found(&mut self, probe: usize, found: usize) -> Bucket<T> {
13731378
// index `probe` and entry `found` is to be removed
@@ -1587,7 +1592,12 @@ impl<T> HeaderMap<T> {
15871592

15881593
/// Removes the `ExtraValue` at the given index.
15891594
#[inline]
1590-
fn remove_extra_value<T>(mut raw_links: RawLinks<T>, extra_values: &mut Vec<ExtraValue<T>>, idx: usize) -> ExtraValue<T> {
1595+
fn remove_extra_value<T>(
1596+
mut raw_links: RawLinks<T>,
1597+
extra_values: &mut Vec<ExtraValue<T>>,
1598+
idx: usize)
1599+
-> ExtraValue<T>
1600+
{
15911601
let prev;
15921602
let next;
15931603

@@ -1703,6 +1713,26 @@ fn remove_extra_value<T>(mut raw_links: RawLinks<T>, extra_values: &mut Vec<Extr
17031713
extra
17041714
}
17051715

1716+
fn drain_all_extra_values<T>(
1717+
raw_links: RawLinks<T>,
1718+
extra_values: &mut Vec<ExtraValue<T>>,
1719+
mut head: usize)
1720+
-> Vec<T>
1721+
{
1722+
let mut vec = Vec::new();
1723+
loop {
1724+
let extra = remove_extra_value(raw_links, extra_values, head);
1725+
vec.push(extra.value);
1726+
1727+
if let Link::Extra(idx) = extra.next {
1728+
head = idx;
1729+
} else {
1730+
break;
1731+
}
1732+
}
1733+
vec
1734+
}
1735+
17061736
impl<'a, T> IntoIterator for &'a HeaderMap<T> {
17071737
type Item = (&'a HeaderName, &'a T);
17081738
type IntoIter = Iter<'a, T>;
@@ -2922,12 +2952,12 @@ impl<'a, T> OccupiedEntry<'a, T> {
29222952
/// assert!(!map.contains_key("host"));
29232953
/// ```
29242954
pub fn remove_entry(self) -> (HeaderName, T) {
2925-
let entry = self.map.remove_found(self.probe, self.index);
2926-
2927-
if let Some(links) = entry.links {
2955+
if let Some(links) = self.map.entries[self.index].links {
29282956
self.map.remove_all_extra_values(links.next);
29292957
}
29302958

2959+
let entry = self.map.remove_found(self.probe, self.index);
2960+
29312961
(entry.key, entry.value)
29322962
}
29332963

@@ -2936,14 +2966,19 @@ impl<'a, T> OccupiedEntry<'a, T> {
29362966
/// The key and all values associated with the entry are removed and
29372967
/// returned.
29382968
pub fn remove_entry_mult(self) -> (HeaderName, ValueDrain<'a, T>) {
2939-
let entry = self.map.remove_found(self.probe, self.index);
29402969
let raw_links = self.map.raw_links();
2941-
let extra_values = &mut self.map.extra_values as *mut _;
2970+
let extra_values = &mut self.map.extra_values;
2971+
2972+
let next = self.map.entries[self.index].links.map(|l| {
2973+
drain_all_extra_values(raw_links, extra_values, l.next)
2974+
.into_iter()
2975+
});
2976+
2977+
let entry = self.map.remove_found(self.probe, self.index);
2978+
29422979
let drain = ValueDrain {
2943-
raw_links,
2944-
extra_values,
29452980
first: Some(entry.value),
2946-
next: entry.links.map(|l| l.next),
2981+
next,
29472982
lt: PhantomData,
29482983
};
29492984
(entry.key, drain)
@@ -3036,31 +3071,26 @@ impl<'a, T> Iterator for ValueDrain<'a, T> {
30363071
fn next(&mut self) -> Option<T> {
30373072
if self.first.is_some() {
30383073
self.first.take()
3039-
} else if let Some(next) = self.next {
3040-
// Remove the extra value
3041-
let extra = unsafe {
3042-
remove_extra_value(self.raw_links, &mut *self.extra_values, next)
3043-
};
3044-
3045-
match extra.next {
3046-
Link::Extra(idx) => self.next = Some(idx),
3047-
Link::Entry(_) => self.next = None,
3048-
}
3049-
3050-
Some(extra.value)
3074+
} else if let Some(ref mut extras) = self.next {
3075+
extras.next()
30513076
} else {
30523077
None
30533078
}
30543079
}
30553080

30563081
fn size_hint(&self) -> (usize, Option<usize>) {
3057-
match (&self.first, self.next) {
3082+
match (&self.first, &self.next) {
30583083
// Exactly 1
3059-
(&Some(_), None) => (1, Some(1)),
3060-
// At least 1
3061-
(&_, Some(_)) => (1, None),
3084+
(&Some(_), &None) => (1, Some(1)),
3085+
// 1 + extras
3086+
(&Some(_), &Some(ref extras)) => {
3087+
let (l, u) = extras.size_hint();
3088+
(l + 1, u.map(|u| u + 1))
3089+
},
3090+
// Extras only
3091+
(&None, &Some(ref extras)) => extras.size_hint(),
30623092
// No more
3063-
(&None, None) => (0, Some(0)),
3093+
(&None, &None) => (0, Some(0)),
30643094
}
30653095
}
30663096
}

0 commit comments

Comments
 (0)