From 2a1378d3eb073026468063fd354d90511b61def0 Mon Sep 17 00:00:00 2001 From: bluss Date: Wed, 21 Sep 2016 14:17:57 +0200 Subject: [PATCH] Fix bounds checking in ArrayVec::insert(index, element) Must be `index <= len && index < capacity` --- src/lib.rs | 6 +++++- tests/tests.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 15dfc7f..1bb33ae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -179,6 +179,10 @@ impl ArrayVec { /// /// Return `None` if no element is shifted out. /// + /// `index` must be <= `self.len()` and < `self.capacity()`. Note that any + /// out of bounds index insert results in the element being "shifted out" + /// and returned directly. + /// /// ``` /// use arrayvec::ArrayVec; /// @@ -192,7 +196,7 @@ impl ArrayVec { /// /// ``` pub fn insert(&mut self, index: usize, element: A::Item) -> Option { - if index >= self.capacity() { + if index > self.len() || index == self.capacity() { return Some(element); } let mut ret = None; diff --git a/tests/tests.rs b/tests/tests.rs index aadacce..3dc204c 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -355,3 +355,60 @@ fn test_string_clone() { s.clone_from(&t); assert_eq!(&t, &s); } + + +#[test] +fn test_insert_at_length() { + let mut v = ArrayVec::<[_; 8]>::new(); + let result1 = v.insert(0, "a"); + let result2 = v.insert(1, "b"); + assert!(result1.is_none() && result2.is_none()); + assert_eq!(&v[..], &["a", "b"]); +} + +#[test] +fn test_insert_out_of_bounds() { + let mut v = ArrayVec::<[_; 8]>::new(); + let result = v.insert(1, "test"); + assert_eq!(result, Some("test")); + assert_eq!(v.len(), 0); + + let mut u = ArrayVec::from([1, 2, 3, 4]); + let ret = u.insert(3, 99); + assert_eq!(&u[..], &[1, 2, 3, 99]); + assert_eq!(ret, Some(4)); + let ret = u.insert(4, 77); + assert_eq!(&u[..], &[1, 2, 3, 99]); + assert_eq!(ret, Some(77)); +} + +#[test] +fn test_drop_in_insert() { + use std::cell::Cell; + + let flag = &Cell::new(0); + + struct Bump<'a>(&'a Cell); + + impl<'a> Drop for Bump<'a> { + fn drop(&mut self) { + let n = self.0.get(); + self.0.set(n + 1); + } + } + + flag.set(0); + + { + let mut array = ArrayVec::<[_; 2]>::new(); + array.push(Bump(flag)); + array.insert(0, Bump(flag)); + assert_eq!(flag.get(), 0); + let ret = array.insert(1, Bump(flag)); + assert_eq!(flag.get(), 0); + assert!(ret.is_some()); + drop(ret); + assert_eq!(flag.get(), 1); + } + assert_eq!(flag.get(), 3); +}