Skip to content

Commit d547de9

Browse files
lilyballalexcrichton
authored andcommitted
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.
1 parent 4bcc4d7 commit d547de9

File tree

1 file changed

+40
-5
lines changed

1 file changed

+40
-5
lines changed

src/libstd/vec.rs

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -635,14 +635,14 @@ impl<T> Vec<T> {
635635
/// ```
636636
pub fn truncate(&mut self, len: uint) {
637637
unsafe {
638-
let mut i = len;
639638
// drop any extra elements
640-
while i < self.len {
641-
ptr::read(self.as_slice().unsafe_ref(i));
642-
i += 1;
639+
while len < self.len {
640+
// decrement len before the read(), so a failure on Drop doesn't
641+
// re-drop the just-failed value.
642+
self.len -= 1;
643+
ptr::read(self.as_slice().unsafe_ref(self.len));
643644
}
644645
}
645-
self.len = len;
646646
}
647647

648648
/// Work with `self` as a mutable slice.
@@ -1862,4 +1862,39 @@ mod tests {
18621862
assert_eq!(b[0].x, 42);
18631863
assert_eq!(b[1].x, 84);
18641864
}
1865+
1866+
#[test]
1867+
fn test_vec_truncate_drop() {
1868+
static mut drops: uint = 0;
1869+
struct Elem(int);
1870+
impl Drop for Elem {
1871+
fn drop(&mut self) {
1872+
unsafe { drops += 1; }
1873+
}
1874+
}
1875+
1876+
let mut v = vec![Elem(1), Elem(2), Elem(3), Elem(4), Elem(5)];
1877+
assert_eq!(unsafe { drops }, 0);
1878+
v.truncate(3);
1879+
assert_eq!(unsafe { drops }, 2);
1880+
v.truncate(0);
1881+
assert_eq!(unsafe { drops }, 5);
1882+
}
1883+
1884+
#[test]
1885+
#[should_fail]
1886+
fn test_vec_truncate_fail() {
1887+
struct BadElem(int);
1888+
impl Drop for BadElem {
1889+
fn drop(&mut self) {
1890+
let BadElem(ref mut x) = *self;
1891+
if *x == 0xbadbeef {
1892+
fail!("BadElem failure: 0xbadbeef")
1893+
}
1894+
}
1895+
}
1896+
1897+
let mut v = vec![BadElem(1), BadElem(2), BadElem(0xbadbeef), BadElem(4)];
1898+
v.truncate(0);
1899+
}
18651900
}

0 commit comments

Comments
 (0)