Skip to content

Commit 63ecdeb

Browse files
authored
Merge pull request #175 from bluss/extend-panic-on-capacity-error
Panic in .extend() and from_iter on capacity exceeded
2 parents bcffbf9 + a554ea2 commit 63ecdeb

File tree

2 files changed

+97
-48
lines changed

2 files changed

+97
-48
lines changed

src/arrayvec.rs

Lines changed: 70 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -704,7 +704,7 @@ impl<T, const CAP: usize> std::convert::TryFrom<&[T]> for ArrayVec<T, CAP>
704704
Err(CapacityError::new(()))
705705
} else {
706706
let mut array = Self::new();
707-
array.extend(slice.iter().cloned());
707+
array.extend_from_slice(slice);
708708
Ok(array)
709709
}
710710
}
@@ -931,39 +931,75 @@ impl<T, Data, F> Drop for ScopeExitGuard<T, Data, F>
931931

932932
/// Extend the `ArrayVec` with an iterator.
933933
///
934-
/// Does not extract more items than there is space for. No error
935-
/// occurs if there are more iterator elements.
934+
/// ***Panics*** if extending the vector exceeds its capacity.
936935
impl<T, const CAP: usize> Extend<T> for ArrayVec<T, CAP> {
936+
/// Extend the `ArrayVec` with an iterator.
937+
///
938+
/// ***Panics*** if extending the vector exceeds its capacity.
937939
fn extend<I: IntoIterator<Item=T>>(&mut self, iter: I) {
938-
let take = self.capacity() - self.len();
939940
unsafe {
940-
let len = self.len();
941-
let mut ptr = raw_ptr_add(self.as_mut_ptr(), len);
942-
let end_ptr = raw_ptr_add(ptr, take);
943-
// Keep the length in a separate variable, write it back on scope
944-
// exit. To help the compiler with alias analysis and stuff.
945-
// We update the length to handle panic in the iteration of the
946-
// user's iterator, without dropping any elements on the floor.
947-
let mut guard = ScopeExitGuard {
948-
value: &mut self.len,
949-
data: len,
950-
f: move |&len, self_len| {
951-
**self_len = len;
952-
}
953-
};
954-
let mut iter = iter.into_iter();
955-
loop {
956-
if ptr == end_ptr { break; }
957-
if let Some(elt) = iter.next() {
958-
raw_ptr_write(ptr, elt);
959-
ptr = raw_ptr_add(ptr, 1);
960-
guard.data += 1;
961-
} else {
962-
break;
963-
}
941+
self.extend_from_iter::<_, true>(iter)
942+
}
943+
}
944+
}
945+
946+
#[inline(never)]
947+
#[cold]
948+
fn extend_panic() {
949+
panic!("ArrayVec: capacity exceeded in extend/from_iter");
950+
}
951+
952+
impl<T, const CAP: usize> ArrayVec<T, CAP> {
953+
/// Extend the arrayvec from the iterable.
954+
///
955+
/// ## Safety
956+
///
957+
/// Unsafe because if CHECK is false, the length of the input is not checked.
958+
/// The caller must ensure the length of the input fits in the capacity.
959+
pub(crate) unsafe fn extend_from_iter<I, const CHECK: bool>(&mut self, iterable: I)
960+
where I: IntoIterator<Item = T>
961+
{
962+
let take = self.capacity() - self.len();
963+
let len = self.len();
964+
let mut ptr = raw_ptr_add(self.as_mut_ptr(), len);
965+
let end_ptr = raw_ptr_add(ptr, take);
966+
// Keep the length in a separate variable, write it back on scope
967+
// exit. To help the compiler with alias analysis and stuff.
968+
// We update the length to handle panic in the iteration of the
969+
// user's iterator, without dropping any elements on the floor.
970+
let mut guard = ScopeExitGuard {
971+
value: &mut self.len,
972+
data: len,
973+
f: move |&len, self_len| {
974+
**self_len = len;
975+
}
976+
};
977+
let mut iter = iterable.into_iter();
978+
loop {
979+
if let Some(elt) = iter.next() {
980+
if ptr == end_ptr && CHECK { extend_panic(); }
981+
debug_assert_ne!(ptr, end_ptr);
982+
ptr.write(elt);
983+
ptr = raw_ptr_add(ptr, 1);
984+
guard.data += 1;
985+
} else {
986+
return; // success
964987
}
965988
}
966989
}
990+
991+
/// Extend the ArrayVec with clones of elements from the slice;
992+
/// the length of the slice must be <= the remaining capacity in the arrayvec.
993+
pub(crate) fn extend_from_slice(&mut self, slice: &[T])
994+
where T: Clone
995+
{
996+
let take = self.capacity() - self.len();
997+
debug_assert!(slice.len() <= take);
998+
unsafe {
999+
let slice = if take < slice.len() { &slice[..take] } else { slice };
1000+
self.extend_from_iter::<_, false>(slice.iter().cloned());
1001+
}
1002+
}
9671003
}
9681004

9691005
/// Rawptr add but uses arithmetic distance for ZST
@@ -976,19 +1012,13 @@ unsafe fn raw_ptr_add<T>(ptr: *mut T, offset: usize) -> *mut T {
9761012
}
9771013
}
9781014

979-
unsafe fn raw_ptr_write<T>(ptr: *mut T, value: T) {
980-
if mem::size_of::<T>() == 0 {
981-
/* nothing */
982-
} else {
983-
ptr::write(ptr, value)
984-
}
985-
}
986-
9871015
/// Create an `ArrayVec` from an iterator.
9881016
///
989-
/// Does not extract more items than there is space for. No error
990-
/// occurs if there are more iterator elements.
1017+
/// ***Panics*** if the number of elements in the iterator exceeds the arrayvec's capacity.
9911018
impl<T, const CAP: usize> iter::FromIterator<T> for ArrayVec<T, CAP> {
1019+
/// Create an `ArrayVec` from an iterator.
1020+
///
1021+
/// ***Panics*** if the number of elements in the iterator exceeds the arrayvec's capacity.
9921022
fn from_iter<I: IntoIterator<Item=T>>(iter: I) -> Self {
9931023
let mut array = ArrayVec::new();
9941024
array.extend(iter);
@@ -1014,8 +1044,8 @@ impl<T, const CAP: usize> Clone for ArrayVec<T, CAP>
10141044
self.pop();
10151045
}
10161046
} else {
1017-
let rhs_elems = rhs[self.len()..].iter().cloned();
1018-
self.extend(rhs_elems);
1047+
let rhs_elems = &rhs[self.len()..];
1048+
self.extend_from_slice(rhs_elems);
10191049
}
10201050
}
10211051
}

tests/tests.rs

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -251,11 +251,11 @@ fn test_drop_panics() {
251251
fn test_extend() {
252252
let mut range = 0..10;
253253

254-
let mut array: ArrayVec<_, 5> = range.by_ref().collect();
254+
let mut array: ArrayVec<_, 5> = range.by_ref().take(5).collect();
255255
assert_eq!(&array[..], &[0, 1, 2, 3, 4]);
256256
assert_eq!(range.next(), Some(5));
257257

258-
array.extend(range.by_ref());
258+
array.extend(range.by_ref().take(0));
259259
assert_eq!(range.next(), Some(6));
260260

261261
let mut array: ArrayVec<_, 10> = (0..3).collect();
@@ -264,6 +264,25 @@ fn test_extend() {
264264
assert_eq!(&array[..], &[0, 1, 2, 3, 4]);
265265
}
266266

267+
#[should_panic]
268+
#[test]
269+
fn test_extend_capacity_panic_1() {
270+
let mut range = 0..10;
271+
272+
let _: ArrayVec<_, 5> = range.by_ref().collect();
273+
}
274+
275+
#[should_panic]
276+
#[test]
277+
fn test_extend_capacity_panic_2() {
278+
let mut range = 0..10;
279+
280+
let mut array: ArrayVec<_, 5> = range.by_ref().take(5).collect();
281+
assert_eq!(&array[..], &[0, 1, 2, 3, 4]);
282+
assert_eq!(range.next(), Some(5));
283+
array.extend(range.by_ref().take(1));
284+
}
285+
267286
#[test]
268287
fn test_is_send_sync() {
269288
let data = ArrayVec::<Vec<i32>, 5>::new();
@@ -304,7 +323,7 @@ fn test_drain() {
304323
v.drain(0..7);
305324
assert_eq!(&v[..], &[]);
306325

307-
v.extend(0..);
326+
v.extend(0..8);
308327
v.drain(1..4);
309328
assert_eq!(&v[..], &[0, 4, 5, 6, 7]);
310329
let u: ArrayVec<_, 3> = v.drain(1..4).rev().collect();
@@ -320,7 +339,7 @@ fn test_drain_range_inclusive() {
320339
v.drain(0..=7);
321340
assert_eq!(&v[..], &[]);
322341

323-
v.extend(0..);
342+
v.extend(0..8);
324343
v.drain(1..=4);
325344
assert_eq!(&v[..], &[0, 5, 6, 7]);
326345
let u: ArrayVec<_, 3> = v.drain(1..=2).rev().collect();
@@ -436,9 +455,9 @@ fn test_into_inner_2() {
436455
}
437456

438457
#[test]
439-
fn test_into_inner_3_() {
458+
fn test_into_inner_3() {
440459
let mut v = ArrayVec::<i32, 4>::new();
441-
v.extend(1..);
460+
v.extend(1..=4);
442461
assert_eq!(v.into_inner().unwrap(), [1, 2, 3, 4]);
443462
}
444463

@@ -672,11 +691,11 @@ fn test_extend_zst() {
672691
#[derive(Copy, Clone, PartialEq, Debug)]
673692
struct Z; // Zero sized type
674693

675-
let mut array: ArrayVec<_, 5> = range.by_ref().map(|_| Z).collect();
694+
let mut array: ArrayVec<_, 5> = range.by_ref().take(5).map(|_| Z).collect();
676695
assert_eq!(&array[..], &[Z; 5]);
677696
assert_eq!(range.next(), Some(5));
678697

679-
array.extend(range.by_ref().map(|_| Z));
698+
array.extend(range.by_ref().take(0).map(|_| Z));
680699
assert_eq!(range.next(), Some(6));
681700

682701
let mut array: ArrayVec<_, 10> = (0..3).map(|_| Z).collect();

0 commit comments

Comments
 (0)