Skip to content

Commit 9122b76

Browse files
committed
Auto merge of #78373 - matthewjasper:drop-on-into, r=pnkfelix
Don't leak return value after panic in drop Closes #47949
2 parents 551a2c6 + 4fef391 commit 9122b76

32 files changed

+11088
-10909
lines changed

Diff for: compiler/rustc_mir_build/src/build/block.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::build::ForGuard::OutsideGuard;
33
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
44
use crate::thir::*;
55
use rustc_hir as hir;
6+
use rustc_middle::middle::region;
67
use rustc_middle::mir::*;
78
use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN;
89
use rustc_session::lint::Level;
@@ -12,6 +13,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1213
crate fn ast_block(
1314
&mut self,
1415
destination: Place<'tcx>,
16+
scope: Option<region::Scope>,
1517
block: BasicBlock,
1618
ast_block: &'tcx hir::Block<'tcx>,
1719
source_info: SourceInfo,
@@ -28,9 +30,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2830
self.in_opt_scope(opt_destruction_scope.map(|de| (de, source_info)), move |this| {
2931
this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
3032
if targeted_by_break {
31-
this.in_breakable_scope(None, destination, span, |this| {
33+
this.in_breakable_scope(None, destination, scope, span, |this| {
3234
Some(this.ast_block_stmts(
3335
destination,
36+
scope,
3437
block,
3538
span,
3639
stmts,
@@ -39,7 +42,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3942
))
4043
})
4144
} else {
42-
this.ast_block_stmts(destination, block, span, stmts, expr, safety_mode)
45+
this.ast_block_stmts(destination, scope, block, span, stmts, expr, safety_mode)
4346
}
4447
})
4548
})
@@ -48,6 +51,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
4851
fn ast_block_stmts(
4952
&mut self,
5053
destination: Place<'tcx>,
54+
scope: Option<region::Scope>,
5155
mut block: BasicBlock,
5256
span: Span,
5357
stmts: Vec<StmtRef<'tcx>>,
@@ -182,7 +186,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
182186
};
183187
this.block_context.push(BlockFrame::TailExpr { tail_result_is_ignored, span });
184188

185-
unpack!(block = this.into(destination, block, expr));
189+
unpack!(block = this.into(destination, scope, block, expr));
186190
let popped = this.block_context.pop();
187191

188192
assert!(popped.map_or(false, |bf| bf.is_tail_expr()));

Diff for: compiler/rustc_mir_build/src/build/expr/as_rvalue.rs

+16-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ use rustc_middle::mir::*;
1111
use rustc_middle::ty::{self, Ty, UpvarSubsts};
1212
use rustc_span::Span;
1313

14+
use std::slice;
15+
1416
impl<'a, 'tcx> Builder<'a, 'tcx> {
1517
/// Returns an rvalue suitable for use until the end of the current
1618
/// scope expression.
@@ -112,12 +114,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
112114
let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty);
113115
this.cfg.push_assign(block, source_info, Place::from(result), box_);
114116

115-
// initialize the box contents:
117+
// Initialize the box contents. No scope is needed since the
118+
// `Box` is already scheduled to be dropped.
116119
unpack!(
117-
block =
118-
this.into(this.hir.tcx().mk_place_deref(Place::from(result)), block, value)
120+
block = this.into(
121+
this.hir.tcx().mk_place_deref(Place::from(result)),
122+
None,
123+
block,
124+
value,
125+
)
119126
);
120-
block.and(Rvalue::Use(Operand::Move(Place::from(result))))
127+
let result_operand = Operand::Move(Place::from(result));
128+
this.record_operands_moved(slice::from_ref(&result_operand));
129+
block.and(Rvalue::Use(result_operand))
121130
}
122131
ExprKind::Cast { source } => {
123132
let source = unpack!(block = this.as_operand(block, scope, source));
@@ -161,6 +170,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
161170
.map(|f| unpack!(block = this.as_operand(block, scope, f)))
162171
.collect();
163172

173+
this.record_operands_moved(&fields);
164174
block.and(Rvalue::Aggregate(box AggregateKind::Array(el_ty), fields))
165175
}
166176
ExprKind::Tuple { fields } => {
@@ -171,6 +181,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
171181
.map(|f| unpack!(block = this.as_operand(block, scope, f)))
172182
.collect();
173183

184+
this.record_operands_moved(&fields);
174185
block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields))
175186
}
176187
ExprKind::Closure { closure_id, substs, upvars, movability } => {
@@ -222,6 +233,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
222233
}
223234
UpvarSubsts::Closure(substs) => box AggregateKind::Closure(closure_id, substs),
224235
};
236+
this.record_operands_moved(&operands);
225237
block.and(Rvalue::Aggregate(result, operands))
226238
}
227239
ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {

Diff for: compiler/rustc_mir_build/src/build/expr/as_temp.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
114114
}
115115
}
116116

117-
unpack!(block = this.into(temp_place, block, expr));
118-
119-
if let Some(temp_lifetime) = temp_lifetime {
120-
this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value);
121-
}
117+
unpack!(block = this.into(temp_place, temp_lifetime, block, expr));
122118

123119
block.and(temp)
124120
}

Diff for: compiler/rustc_mir_build/src/build/expr/into.rs

+70-29
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,37 @@
11
//! See docs in build/expr/mod.rs
22
33
use crate::build::expr::category::{Category, RvalueFunc};
4+
use crate::build::scope::DropKind;
45
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
56
use crate::thir::*;
67
use rustc_ast::InlineAsmOptions;
78
use rustc_data_structures::fx::FxHashMap;
89
use rustc_data_structures::stack::ensure_sufficient_stack;
910
use rustc_hir as hir;
11+
use rustc_middle::middle::region;
1012
use rustc_middle::mir::*;
1113
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation};
1214
use rustc_span::symbol::sym;
13-
1415
use rustc_target::spec::abi::Abi;
1516

17+
use std::slice;
18+
1619
impl<'a, 'tcx> Builder<'a, 'tcx> {
1720
/// Compile `expr`, storing the result into `destination`, which
1821
/// is assumed to be uninitialized.
22+
/// If a `drop_scope` is provided, `destination` is scheduled to be dropped
23+
/// in `scope` once it has been initialized.
1924
crate fn into_expr(
2025
&mut self,
2126
destination: Place<'tcx>,
27+
scope: Option<region::Scope>,
2228
mut block: BasicBlock,
2329
expr: Expr<'tcx>,
2430
) -> BlockAnd<()> {
25-
debug!("into_expr(destination={:?}, block={:?}, expr={:?})", destination, block, expr);
31+
debug!(
32+
"into_expr(destination={:?}, scope={:?}, block={:?}, expr={:?})",
33+
destination, scope, block, expr
34+
);
2635

2736
// since we frequently have to reference `self` from within a
2837
// closure, where `self` would be shadowed, it's easier to
@@ -37,6 +46,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3746
_ => false,
3847
};
3948

49+
let schedule_drop = move |this: &mut Self| {
50+
if let Some(drop_scope) = scope {
51+
let local =
52+
destination.as_local().expect("cannot schedule drop of non-Local place");
53+
this.schedule_drop(expr_span, drop_scope, local, DropKind::Value);
54+
}
55+
};
56+
4057
if !expr_is_block_or_scope {
4158
this.block_context.push(BlockFrame::SubExpr);
4259
}
@@ -46,15 +63,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
4663
let region_scope = (region_scope, source_info);
4764
ensure_sufficient_stack(|| {
4865
this.in_scope(region_scope, lint_level, |this| {
49-
this.into(destination, block, value)
66+
this.into(destination, scope, block, value)
5067
})
5168
})
5269
}
5370
ExprKind::Block { body: ast_block } => {
54-
this.ast_block(destination, block, ast_block, source_info)
71+
this.ast_block(destination, scope, block, ast_block, source_info)
5572
}
5673
ExprKind::Match { scrutinee, arms } => {
57-
this.match_expr(destination, expr_span, block, scrutinee, arms)
74+
this.match_expr(destination, scope, expr_span, block, scrutinee, arms)
5875
}
5976
ExprKind::NeverToAny { source } => {
6077
let source = this.hir.mirror(source);
@@ -66,6 +83,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
6683

6784
// This is an optimization. If the expression was a call then we already have an
6885
// unreachable block. Don't bother to terminate it and create a new one.
86+
schedule_drop(this);
6987
if is_call {
7088
block.unit()
7189
} else {
@@ -141,26 +159,35 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
141159
// Start the loop.
142160
this.cfg.goto(block, source_info, loop_block);
143161

144-
this.in_breakable_scope(Some(loop_block), destination, expr_span, move |this| {
145-
// conduct the test, if necessary
146-
let body_block = this.cfg.start_new_block();
147-
this.cfg.terminate(
148-
loop_block,
149-
source_info,
150-
TerminatorKind::FalseUnwind { real_target: body_block, unwind: None },
151-
);
152-
this.diverge_from(loop_block);
153-
154-
// The “return” value of the loop body must always be an unit. We therefore
155-
// introduce a unit temporary as the destination for the loop body.
156-
let tmp = this.get_unit_temp();
157-
// Execute the body, branching back to the test.
158-
let body_block_end = unpack!(this.into(tmp, body_block, body));
159-
this.cfg.goto(body_block_end, source_info, loop_block);
160-
161-
// Loops are only exited by `break` expressions.
162-
None
163-
})
162+
this.in_breakable_scope(
163+
Some(loop_block),
164+
destination,
165+
scope,
166+
expr_span,
167+
move |this| {
168+
// conduct the test, if necessary
169+
let body_block = this.cfg.start_new_block();
170+
this.cfg.terminate(
171+
loop_block,
172+
source_info,
173+
TerminatorKind::FalseUnwind { real_target: body_block, unwind: None },
174+
);
175+
this.diverge_from(loop_block);
176+
177+
// The “return” value of the loop body must always be an unit. We therefore
178+
// introduce a unit temporary as the destination for the loop body.
179+
let tmp = this.get_unit_temp();
180+
// Execute the body, branching back to the test.
181+
// We don't need to provide a drop scope because `tmp`
182+
// has type `()`.
183+
let body_block_end = unpack!(this.into(tmp, None, body_block, body));
184+
this.cfg.goto(body_block_end, source_info, loop_block);
185+
schedule_drop(this);
186+
187+
// Loops are only exited by `break` expressions.
188+
None
189+
},
190+
)
164191
}
165192
ExprKind::Call { ty, fun, args, from_hir_call, fn_span } => {
166193
let intrinsic = match *ty.kind() {
@@ -192,8 +219,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
192219
.local_decls
193220
.push(LocalDecl::with_source_info(ptr_ty, source_info).internal());
194221
let ptr_temp = Place::from(ptr_temp);
195-
let block = unpack!(this.into(ptr_temp, block, ptr));
196-
this.into(this.hir.tcx().mk_place_deref(ptr_temp), block, val)
222+
// No need for a scope, ptr_temp doesn't need drop
223+
let block = unpack!(this.into(ptr_temp, None, block, ptr));
224+
// Maybe we should provide a scope here so that
225+
// `move_val_init` wouldn't leak on panic even with an
226+
// arbitrary `val` expression, but `schedule_drop`,
227+
// borrowck and drop elaboration all prevent us from
228+
// dropping `ptr_temp.deref()`.
229+
this.into(this.hir.tcx().mk_place_deref(ptr_temp), None, block, val)
197230
} else {
198231
let args: Vec<_> = args
199232
.into_iter()
@@ -226,10 +259,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
226259
},
227260
);
228261
this.diverge_from(block);
262+
schedule_drop(this);
229263
success.unit()
230264
}
231265
}
232-
ExprKind::Use { source } => this.into(destination, block, source),
266+
ExprKind::Use { source } => this.into(destination, scope, block, source),
233267
ExprKind::Borrow { arg, borrow_kind } => {
234268
// We don't do this in `as_rvalue` because we use `as_place`
235269
// for borrow expressions, so we cannot create an `RValue` that
@@ -271,7 +305,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
271305

272306
let field_names = this.hir.all_fields(adt_def, variant_index);
273307

274-
let fields = if let Some(FruInfo { base, field_types }) = base {
308+
let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base {
275309
let base = unpack!(block = this.as_place(block, base));
276310

277311
// MIR does not natively support FRU, so for each
@@ -306,12 +340,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
306340
user_ty,
307341
active_field_index,
308342
);
343+
this.record_operands_moved(&fields);
309344
this.cfg.push_assign(
310345
block,
311346
source_info,
312347
destination,
313348
Rvalue::Aggregate(adt, fields),
314349
);
350+
schedule_drop(this);
315351
block.unit()
316352
}
317353
ExprKind::InlineAsm { template, operands, options, line_spans } => {
@@ -408,6 +444,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
408444
let place = unpack!(block = this.as_place(block, expr));
409445
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
410446
this.cfg.push_assign(block, source_info, destination, rvalue);
447+
schedule_drop(this);
411448
block.unit()
412449
}
413450
ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Field { .. } => {
@@ -425,19 +462,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
425462
let place = unpack!(block = this.as_place(block, expr));
426463
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
427464
this.cfg.push_assign(block, source_info, destination, rvalue);
465+
schedule_drop(this);
428466
block.unit()
429467
}
430468

431469
ExprKind::Yield { value } => {
432470
let scope = this.local_scope();
433471
let value = unpack!(block = this.as_operand(block, scope, value));
434472
let resume = this.cfg.start_new_block();
473+
this.record_operands_moved(slice::from_ref(&value));
435474
this.cfg.terminate(
436475
block,
437476
source_info,
438477
TerminatorKind::Yield { value, resume, resume_arg: destination, drop: None },
439478
);
440479
this.generator_drop_cleanup(block);
480+
schedule_drop(this);
441481
resume.unit()
442482
}
443483

@@ -469,6 +509,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
469509

470510
let rvalue = unpack!(block = this.as_local_rvalue(block, expr));
471511
this.cfg.push_assign(block, source_info, destination, rvalue);
512+
schedule_drop(this);
472513
block.unit()
473514
}
474515
};

Diff for: compiler/rustc_mir_build/src/build/expr/stmt.rs

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
33
use crate::thir::*;
44
use rustc_middle::middle::region;
55
use rustc_middle::mir::*;
6+
use std::slice;
67

78
impl<'a, 'tcx> Builder<'a, 'tcx> {
89
/// Builds a block of MIR statements to evaluate the THIR `expr`.
@@ -46,6 +47,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
4647
if this.hir.needs_drop(lhs.ty) {
4748
let rhs = unpack!(block = this.as_local_operand(block, rhs));
4849
let lhs = unpack!(block = this.as_place(block, lhs));
50+
this.record_operands_moved(slice::from_ref(&rhs));
4951
unpack!(block = this.build_drop_and_replace(block, lhs_span, lhs, rhs));
5052
} else {
5153
let rhs = unpack!(block = this.as_local_rvalue(block, rhs));

0 commit comments

Comments
 (0)