Skip to content

Commit fbaf095

Browse files
committed
Fix panic safety issue when an element panics 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
1 parent bff26fc commit fbaf095

File tree

1 file changed

+19
-11
lines changed

1 file changed

+19
-11
lines changed

lib.rs

Lines changed: 19 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
}

0 commit comments

Comments
 (0)