Skip to content

Commit 5757ac5

Browse files
committed
Fix potential buffer overflow in insert_many
Backport of #254 to the 0.6 branch. Fixes #253.
1 parent 7852204 commit 5757ac5

File tree

2 files changed

+29
-14
lines changed

2 files changed

+29
-14
lines changed

Diff for: Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "smallvec"
3-
version = "0.6.13"
3+
version = "0.6.14"
44
authors = ["Simon Sapin <[email protected]>"]
55
license = "MIT/Apache-2.0"
66
repository = "https://github.com/servo/rust-smallvec"

Diff for: lib.rs

+28-13
Original file line numberDiff line numberDiff line change
@@ -823,7 +823,7 @@ impl<A: Array> SmallVec<A> {
823823
/// Insert multiple elements at position `index`, shifting all following elements toward the
824824
/// back.
825825
pub fn insert_many<I: IntoIterator<Item=A::Item>>(&mut self, index: usize, iterable: I) {
826-
let iter = iterable.into_iter();
826+
let mut iter = iterable.into_iter();
827827
if index == self.len() {
828828
return self.extend(iter);
829829
}
@@ -832,38 +832,40 @@ impl<A: Array> SmallVec<A> {
832832
assert!(lower_size_bound <= std::isize::MAX as usize); // Ensure offset is indexable
833833
assert!(index + lower_size_bound >= index); // Protect against overflow
834834
self.reserve(lower_size_bound);
835+
let mut num_added = 0;
835836

836837
unsafe {
837838
let old_len = self.len();
838839
assert!(index <= old_len);
839-
let mut ptr = self.as_mut_ptr().offset(index as isize);
840+
let ptr = self.as_mut_ptr().offset(index as isize);
840841

841842
// Move the trailing elements.
842843
ptr::copy(ptr, ptr.offset(lower_size_bound as isize), old_len - index);
843844

844845
// In case the iterator panics, don't double-drop the items we just copied above.
845846
self.set_len(index);
846847

847-
let mut num_added = 0;
848-
for element in iter {
849-
let mut cur = ptr.offset(num_added as isize);
850-
if num_added >= lower_size_bound {
851-
// Iterator provided more elements than the hint. Move trailing items again.
852-
self.reserve(1);
853-
ptr = self.as_mut_ptr().offset(index as isize);
854-
cur = ptr.offset(num_added as isize);
855-
ptr::copy(cur, cur.offset(1), old_len - index);
856-
}
848+
while num_added < lower_size_bound {
849+
let element = match iter.next() {
850+
Some(x) => x,
851+
None => break,
852+
};
853+
let cur = ptr.offset(num_added as isize);
857854
ptr::write(cur, element);
858855
num_added += 1;
859856
}
860857
if num_added < lower_size_bound {
861858
// Iterator provided fewer elements than the hint
862859
ptr::copy(ptr.offset(lower_size_bound as isize), ptr.offset(num_added as isize), old_len - index);
863860
}
864-
865861
self.set_len(old_len + num_added);
866862
}
863+
864+
// If the iterator has more than `lower_size_bound` elements, insert the rest one-by-one.
865+
for element in iter {
866+
self.insert(index + num_added, element);
867+
num_added += 1;
868+
}
867869
}
868870

869871
/// Convert a SmallVec to a Vec, without reallocating if the SmallVec has already spilled onto
@@ -2371,4 +2373,17 @@ mod tests {
23712373
assert_eq!(v.capacity(), 4);
23722374
assert_eq!(v[..], [0, 1, 2]);
23732375
}
2376+
2377+
#[test]
2378+
fn test_insert_many_overflow() {
2379+
let mut v: SmallVec<[u8; 1]> = SmallVec::new();
2380+
v.push(123);
2381+
2382+
// Prepare an iterator with small lower bound
2383+
let iter = (0u8..5).filter(|n| n % 2 == 0);
2384+
assert_eq!(iter.size_hint().0, 0);
2385+
2386+
v.insert_many(0, iter);
2387+
assert_eq!(&*v, &[0, 2, 4, 123]);
2388+
}
23742389
}

0 commit comments

Comments
 (0)