Skip to content

Commit a6ca84a

Browse files
committed
look past the next drop for the drop panic target
The previous code would leak data on a drop panic if the immediate next drop was a StorageDead that was followed by another drop.
1 parent a151d37 commit a6ca84a

File tree

2 files changed

+24
-14
lines changed

2 files changed

+24
-14
lines changed

src/librustc_mir/build/scope.rs

+7-9
Original file line numberDiff line numberDiff line change
@@ -836,24 +836,22 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
836836
generator_drop: bool)
837837
-> BlockAnd<()> {
838838
debug!("build_scope_drops({:?} -> {:?})", block, scope);
839-
let mut iter = scope.drops.iter().rev().peekable();
839+
let mut iter = scope.drops.iter().rev();
840840
while let Some(drop_data) = iter.next() {
841841
let source_info = scope.source_info(drop_data.span);
842842
match drop_data.kind {
843843
DropKind::Value { .. } => {
844844
// Try to find the next block with its cached block
845845
// for us to diverge into in case the drop panics.
846-
let on_diverge = iter.peek().iter().filter_map(|dd| {
846+
let on_diverge = iter.clone().filter_map(|dd| {
847847
match dd.kind {
848-
DropKind::Value { cached_block } => {
849-
let result = cached_block.get(generator_drop);
850-
if result.is_none() {
851-
span_bug!(drop_data.span, "cached block not present?")
852-
}
853-
result
854-
},
848+
DropKind::Value { cached_block } => Some(cached_block),
855849
DropKind::Storage => None
856850
}
851+
}).map(|cached_block| {
852+
cached_block
853+
.get(generator_drop)
854+
.unwrap_or_else(|| span_bug!(drop_data.span, "cached block not present?"))
857855
}).next();
858856
// If there’s no `cached_block`s within current scope,
859857
// we must look for one in the enclosing scope.

src/test/run-pass/dynamic-drop.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,17 @@ fn generator(a: &Allocator, run_count: usize) {
177177
}
178178
}
179179

180+
fn mixed_drop_and_nondrop(a: &Allocator) {
181+
// check that destructor panics handle drop
182+
// and non-drop blocks in the same scope correctly.
183+
//
184+
// Surprisingly enough, this used to not work.
185+
let (x, y, z);
186+
x = a.alloc();
187+
y = 5;
188+
z = a.alloc();
189+
}
190+
180191
#[allow(unreachable_code)]
181192
fn vec_unreachable(a: &Allocator) {
182193
let _x = vec![a.alloc(), a.alloc(), a.alloc(), return];
@@ -244,11 +255,12 @@ fn main() {
244255
run_test(|a| field_assignment(a, false));
245256
run_test(|a| field_assignment(a, true));
246257

247-
// FIXME: fix leaks on panics
248-
run_test_nopanic(|a| generator(a, 0));
249-
run_test_nopanic(|a| generator(a, 1));
250-
run_test_nopanic(|a| generator(a, 2));
251-
run_test_nopanic(|a| generator(a, 3));
258+
run_test(|a| generator(a, 0));
259+
run_test(|a| generator(a, 1));
260+
run_test(|a| generator(a, 2));
261+
run_test(|a| generator(a, 3));
262+
263+
run_test(|a| mixed_drop_and_nondrop(a));
252264

253265
run_test_nopanic(|a| union1(a));
254266
}

0 commit comments

Comments
 (0)