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.
This commit is contained in:
parent
a151d37401
commit
a6ca84a383
2 changed files with 24 additions and 14 deletions
|
@ -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.
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue