diff options
| author | Kevin Ballard <kevin@sb.org> | 2014-05-14 14:57:27 -0700 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2014-05-15 13:50:29 -0700 |
| commit | d547de998d33e5b688533f4159ea997c940d9431 (patch) | |
| tree | d2c3c712bb14cda67dbecb92d7d25858fe3a3dab /src/libstd | |
| parent | 4bcc4d76a049a50474764383889e4ede9388da9f (diff) | |
| download | rust-d547de998d33e5b688533f4159ea997c940d9431.tar.gz rust-d547de998d33e5b688533f4159ea997c940d9431.zip | |
Make Vec.truncate() resilient against failure in Drop
If a vector element fails in Drop, Vec needs to make sure it doesn't try to re-drop any elements it already dropped.
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/vec.rs | 45 |
1 files changed, 40 insertions, 5 deletions
diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 528ab72762a..57f8d78948f 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -635,14 +635,14 @@ impl<T> Vec<T> { /// ``` pub fn truncate(&mut self, len: uint) { unsafe { - let mut i = len; // drop any extra elements - while i < self.len { - ptr::read(self.as_slice().unsafe_ref(i)); - i += 1; + while len < self.len { + // decrement len before the read(), so a failure on Drop doesn't + // re-drop the just-failed value. + self.len -= 1; + ptr::read(self.as_slice().unsafe_ref(self.len)); } } - self.len = len; } /// Work with `self` as a mutable slice. @@ -1862,4 +1862,39 @@ mod tests { assert_eq!(b[0].x, 42); assert_eq!(b[1].x, 84); } + + #[test] + fn test_vec_truncate_drop() { + static mut drops: uint = 0; + struct Elem(int); + impl Drop for Elem { + fn drop(&mut self) { + unsafe { drops += 1; } + } + } + + let mut v = vec![Elem(1), Elem(2), Elem(3), Elem(4), Elem(5)]; + assert_eq!(unsafe { drops }, 0); + v.truncate(3); + assert_eq!(unsafe { drops }, 2); + v.truncate(0); + assert_eq!(unsafe { drops }, 5); + } + + #[test] + #[should_fail] + fn test_vec_truncate_fail() { + struct BadElem(int); + impl Drop for BadElem { + fn drop(&mut self) { + let BadElem(ref mut x) = *self; + if *x == 0xbadbeef { + fail!("BadElem failure: 0xbadbeef") + } + } + } + + let mut v = vec![BadElem(1), BadElem(2), BadElem(0xbadbeef), BadElem(4)]; + v.truncate(0); + } } |
