From 5757ac500d4e544485d796b542e4e589749c291b Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Fri, 8 Jan 2021 09:31:27 -0800 Subject: [PATCH] Fix potential buffer overflow in `insert_many` Backport of #254 to the 0.6 branch. Fixes #253. --- Cargo.toml | 2 +- lib.rs | 41 ++++++++++++++++++++++++++++------------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 299a646..de8561c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "smallvec" -version = "0.6.13" +version = "0.6.14" authors = ["Simon Sapin "] license = "MIT/Apache-2.0" repository = "https://github.com/servo/rust-smallvec" diff --git a/lib.rs b/lib.rs index 55278ad..a227cb8 100644 --- a/lib.rs +++ b/lib.rs @@ -823,7 +823,7 @@ impl SmallVec { /// Insert multiple elements at position `index`, shifting all following elements toward the /// back. pub fn insert_many>(&mut self, index: usize, iterable: I) { - let iter = iterable.into_iter(); + let mut iter = iterable.into_iter(); if index == self.len() { return self.extend(iter); } @@ -832,11 +832,12 @@ impl SmallVec { assert!(lower_size_bound <= std::isize::MAX as usize); // Ensure offset is indexable assert!(index + lower_size_bound >= index); // Protect against overflow self.reserve(lower_size_bound); + let mut num_added = 0; unsafe { let old_len = self.len(); assert!(index <= old_len); - let mut ptr = self.as_mut_ptr().offset(index as isize); + let ptr = self.as_mut_ptr().offset(index as isize); // Move the trailing elements. ptr::copy(ptr, ptr.offset(lower_size_bound as isize), old_len - index); @@ -844,16 +845,12 @@ impl SmallVec { // In case the iterator panics, don't double-drop the items we just copied above. self.set_len(index); - let mut num_added = 0; - for element in iter { - let mut cur = ptr.offset(num_added as isize); - if num_added >= lower_size_bound { - // Iterator provided more elements than the hint. Move trailing items again. - self.reserve(1); - ptr = self.as_mut_ptr().offset(index as isize); - cur = ptr.offset(num_added as isize); - ptr::copy(cur, cur.offset(1), old_len - index); - } + while num_added < lower_size_bound { + let element = match iter.next() { + Some(x) => x, + None => break, + }; + let cur = ptr.offset(num_added as isize); ptr::write(cur, element); num_added += 1; } @@ -861,9 +858,14 @@ impl SmallVec { // Iterator provided fewer elements than the hint ptr::copy(ptr.offset(lower_size_bound as isize), ptr.offset(num_added as isize), old_len - index); } - self.set_len(old_len + num_added); } + + // If the iterator has more than `lower_size_bound` elements, insert the rest one-by-one. + for element in iter { + self.insert(index + num_added, element); + num_added += 1; + } } /// Convert a SmallVec to a Vec, without reallocating if the SmallVec has already spilled onto @@ -2371,4 +2373,17 @@ mod tests { assert_eq!(v.capacity(), 4); assert_eq!(v[..], [0, 1, 2]); } + + #[test] + fn test_insert_many_overflow() { + let mut v: SmallVec<[u8; 1]> = SmallVec::new(); + v.push(123); + + // Prepare an iterator with small lower bound + let iter = (0u8..5).filter(|n| n % 2 == 0); + assert_eq!(iter.size_hint().0, 0); + + v.insert_many(0, iter); + assert_eq!(&*v, &[0, 2, 4, 123]); + } }