Skip to content

Commit b5c3e4f

Browse files
author
bors-servo
committed
Auto merge of #15 - bluss:drop-nodrop, r=SimonSapin
Fix panic safety issue in drop The summary is: SmallVec::drop first attempts to drop every element, then it inhibits the drop of the inner array. The panic safety issue is that a panic during drop of an element means the inhibition is never reached, so the inner data can be dropped again. If Drop is split betweeen SmallVec and SmallVecData, this issue is avoided because the SmallVecData drop will be called even in the panic case. This solution incurs the overhead of an additional drop flag on SmallVecData. Fixes #14
2 parents 3e329f0 + fbaf095 commit b5c3e4f

File tree

1 file changed

+36
-11
lines changed

1 file changed

+36
-11
lines changed

lib.rs

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,23 @@ enum SmallVecData<A: Array> {
8383
Heap { ptr: *mut A::Item, capacity: usize },
8484
}
8585

86+
impl<A: Array> Drop for SmallVecData<A> {
87+
fn drop(&mut self) {
88+
unsafe {
89+
match *self {
90+
ref mut inline @ Inline { .. } => {
91+
// Inhibit the array destructor.
92+
ptr::write(inline, Heap {
93+
ptr: ptr::null_mut(),
94+
capacity: 0,
95+
});
96+
}
97+
Heap { ptr, capacity } => deallocate(ptr, capacity),
98+
}
99+
}
100+
}
101+
}
102+
86103

87104
pub struct SmallVec<A: Array> {
88105
len: usize,
@@ -378,22 +395,13 @@ impl<A: Array> SmallVec<A> {
378395

379396
impl<A: Array> Drop for SmallVec<A> {
380397
fn drop(&mut self) {
398+
// Note on panic safety: dropping an element may panic,
399+
// but the inner SmallVecData destructor will still run
381400
unsafe {
382401
let ptr = self.as_ptr();
383402
for i in 0 .. self.len {
384403
ptr::read(ptr.offset(i as isize));
385404
}
386-
387-
match self.data {
388-
Inline { .. } => {
389-
// Inhibit the array destructor.
390-
ptr::write(&mut self.data, Heap {
391-
ptr: ptr::null_mut(),
392-
capacity: 0,
393-
});
394-
}
395-
Heap { ptr, capacity } => deallocate(ptr, capacity),
396-
}
397405
}
398406
}
399407
}
@@ -578,4 +586,21 @@ pub mod tests {
578586

579587
assert_eq!(&v.iter().map(|v| **v).collect::<Vec<_>>(), &[0, 3, 2]);
580588
}
589+
590+
#[test]
591+
#[should_panic]
592+
fn test_drop_panic_smallvec() {
593+
// This test should only panic once, and not double panic,
594+
// which would mean a double drop
595+
struct DropPanic;
596+
597+
impl Drop for DropPanic {
598+
fn drop(&mut self) {
599+
panic!("drop");
600+
}
601+
}
602+
603+
let mut v = SmallVec::<[_; 1]>::new();
604+
v.push(DropPanic);
605+
}
581606
}

0 commit comments

Comments
 (0)