From a6ca84a38340bdbf3c02ba4c7970c9289e5bc946 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 17 Oct 2017 21:37:18 +0300 Subject: [PATCH] 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. --- src/librustc_mir/build/scope.rs | 16 +++++++--------- src/test/run-pass/dynamic-drop.rs | 22 +++++++++++++++++----- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index b88b61f18184..772438d5252c 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -836,24 +836,22 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>, generator_drop: bool) -> BlockAnd<()> { debug!("build_scope_drops({:?} -> {:?})", block, scope); - let mut iter = scope.drops.iter().rev().peekable(); + let mut iter = scope.drops.iter().rev(); while let Some(drop_data) = iter.next() { let source_info = scope.source_info(drop_data.span); match drop_data.kind { DropKind::Value { .. } => { // Try to find the next block with its cached block // for us to diverge into in case the drop panics. - let on_diverge = iter.peek().iter().filter_map(|dd| { + let on_diverge = iter.clone().filter_map(|dd| { match dd.kind { - DropKind::Value { cached_block } => { - let result = cached_block.get(generator_drop); - if result.is_none() { - span_bug!(drop_data.span, "cached block not present?") - } - result - }, + DropKind::Value { cached_block } => Some(cached_block), DropKind::Storage => None } + }).map(|cached_block| { + cached_block + .get(generator_drop) + .unwrap_or_else(|| span_bug!(drop_data.span, "cached block not present?")) }).next(); // If there’s no `cached_block`s within current scope, // we must look for one in the enclosing scope. diff --git a/src/test/run-pass/dynamic-drop.rs b/src/test/run-pass/dynamic-drop.rs index d8b6dbe48f1a..483dbb356ce6 100644 --- a/src/test/run-pass/dynamic-drop.rs +++ b/src/test/run-pass/dynamic-drop.rs @@ -177,6 +177,17 @@ fn generator(a: &Allocator, run_count: usize) { } } +fn mixed_drop_and_nondrop(a: &Allocator) { + // check that destructor panics handle drop + // and non-drop blocks in the same scope correctly. + // + // Surprisingly enough, this used to not work. + let (x, y, z); + x = a.alloc(); + y = 5; + z = a.alloc(); +} + #[allow(unreachable_code)] fn vec_unreachable(a: &Allocator) { let _x = vec![a.alloc(), a.alloc(), a.alloc(), return]; @@ -244,11 +255,12 @@ fn main() { run_test(|a| field_assignment(a, false)); run_test(|a| field_assignment(a, true)); - // FIXME: fix leaks on panics - run_test_nopanic(|a| generator(a, 0)); - run_test_nopanic(|a| generator(a, 1)); - run_test_nopanic(|a| generator(a, 2)); - run_test_nopanic(|a| generator(a, 3)); + run_test(|a| generator(a, 0)); + run_test(|a| generator(a, 1)); + run_test(|a| generator(a, 2)); + run_test(|a| generator(a, 3)); + + run_test(|a| mixed_drop_and_nondrop(a)); run_test_nopanic(|a| union1(a)); }