Skip to content

Commit 4fef391

Browse files
committed
Avoid leaking block expression values
1 parent 7f3e855 commit 4fef391

23 files changed

+10953
-10653
lines changed

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()));

compiler/rustc_mir_build/src/build/expr/as_rvalue.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
114114
let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty);
115115
this.cfg.push_assign(block, source_info, Place::from(result), box_);
116116

117-
// initialize the box contents:
117+
// Initialize the box contents. No scope is needed since the
118+
// `Box` is already scheduled to be dropped.
118119
unpack!(
119-
block =
120-
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+
)
121126
);
122127
let result_operand = Operand::Move(Place::from(result));
123128
this.record_operands_moved(slice::from_ref(&result_operand));

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
}

compiler/rustc_mir_build/src/build/expr/into.rs

+65-27
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
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;
@@ -17,13 +19,19 @@ use std::slice;
1719
impl<'a, 'tcx> Builder<'a, 'tcx> {
1820
/// Compile `expr`, storing the result into `destination`, which
1921
/// 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.
2024
crate fn into_expr(
2125
&mut self,
2226
destination: Place<'tcx>,
27+
scope: Option<region::Scope>,
2328
mut block: BasicBlock,
2429
expr: Expr<'tcx>,
2530
) -> BlockAnd<()> {
26-
debug!("into_expr(destination={:?}, block={:?}, expr={:?})", destination, block, expr);
31+
debug!(
32+
"into_expr(destination={:?}, scope={:?}, block={:?}, expr={:?})",
33+
destination, scope, block, expr
34+
);
2735

2836
// since we frequently have to reference `self` from within a
2937
// closure, where `self` would be shadowed, it's easier to
@@ -38,6 +46,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3846
_ => false,
3947
};
4048

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+
4157
if !expr_is_block_or_scope {
4258
this.block_context.push(BlockFrame::SubExpr);
4359
}
@@ -47,15 +63,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
4763
let region_scope = (region_scope, source_info);
4864
ensure_sufficient_stack(|| {
4965
this.in_scope(region_scope, lint_level, |this| {
50-
this.into(destination, block, value)
66+
this.into(destination, scope, block, value)
5167
})
5268
})
5369
}
5470
ExprKind::Block { body: ast_block } => {
55-
this.ast_block(destination, block, ast_block, source_info)
71+
this.ast_block(destination, scope, block, ast_block, source_info)
5672
}
5773
ExprKind::Match { scrutinee, arms } => {
58-
this.match_expr(destination, expr_span, block, scrutinee, arms)
74+
this.match_expr(destination, scope, expr_span, block, scrutinee, arms)
5975
}
6076
ExprKind::NeverToAny { source } => {
6177
let source = this.hir.mirror(source);
@@ -67,6 +83,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
6783

6884
// This is an optimization. If the expression was a call then we already have an
6985
// unreachable block. Don't bother to terminate it and create a new one.
86+
schedule_drop(this);
7087
if is_call {
7188
block.unit()
7289
} else {
@@ -142,26 +159,35 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
142159
// Start the loop.
143160
this.cfg.goto(block, source_info, loop_block);
144161

145-
this.in_breakable_scope(Some(loop_block), destination, expr_span, move |this| {
146-
// conduct the test, if necessary
147-
let body_block = this.cfg.start_new_block();
148-
this.cfg.terminate(
149-
loop_block,
150-
source_info,
151-
TerminatorKind::FalseUnwind { real_target: body_block, unwind: None },
152-
);
153-
this.diverge_from(loop_block);
154-
155-
// The “return” value of the loop body must always be an unit. We therefore
156-
// introduce a unit temporary as the destination for the loop body.
157-
let tmp = this.get_unit_temp();
158-
// Execute the body, branching back to the test.
159-
let body_block_end = unpack!(this.into(tmp, body_block, body));
160-
this.cfg.goto(body_block_end, source_info, loop_block);
161-
162-
// Loops are only exited by `break` expressions.
163-
None
164-
})
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+
)
165191
}
166192
ExprKind::Call { ty, fun, args, from_hir_call, fn_span } => {
167193
let intrinsic = match *ty.kind() {
@@ -193,8 +219,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
193219
.local_decls
194220
.push(LocalDecl::with_source_info(ptr_ty, source_info).internal());
195221
let ptr_temp = Place::from(ptr_temp);
196-
let block = unpack!(this.into(ptr_temp, block, ptr));
197-
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)
198230
} else {
199231
let args: Vec<_> = args
200232
.into_iter()
@@ -227,10 +259,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
227259
},
228260
);
229261
this.diverge_from(block);
262+
schedule_drop(this);
230263
success.unit()
231264
}
232265
}
233-
ExprKind::Use { source } => this.into(destination, block, source),
266+
ExprKind::Use { source } => this.into(destination, scope, block, source),
234267
ExprKind::Borrow { arg, borrow_kind } => {
235268
// We don't do this in `as_rvalue` because we use `as_place`
236269
// for borrow expressions, so we cannot create an `RValue` that
@@ -314,6 +347,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
314347
destination,
315348
Rvalue::Aggregate(adt, fields),
316349
);
350+
schedule_drop(this);
317351
block.unit()
318352
}
319353
ExprKind::InlineAsm { template, operands, options, line_spans } => {
@@ -410,6 +444,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
410444
let place = unpack!(block = this.as_place(block, expr));
411445
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
412446
this.cfg.push_assign(block, source_info, destination, rvalue);
447+
schedule_drop(this);
413448
block.unit()
414449
}
415450
ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Field { .. } => {
@@ -427,6 +462,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
427462
let place = unpack!(block = this.as_place(block, expr));
428463
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
429464
this.cfg.push_assign(block, source_info, destination, rvalue);
465+
schedule_drop(this);
430466
block.unit()
431467
}
432468

@@ -441,6 +477,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
441477
TerminatorKind::Yield { value, resume, resume_arg: destination, drop: None },
442478
);
443479
this.generator_drop_cleanup(block);
480+
schedule_drop(this);
444481
resume.unit()
445482
}
446483

@@ -472,6 +509,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
472509

473510
let rvalue = unpack!(block = this.as_local_rvalue(block, expr));
474511
this.cfg.push_assign(block, source_info, destination, rvalue);
512+
schedule_drop(this);
475513
block.unit()
476514
}
477515
};

compiler/rustc_mir_build/src/build/into.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
66
77
use crate::build::{BlockAnd, Builder};
88
use crate::thir::*;
9+
use rustc_middle::middle::region;
910
use rustc_middle::mir::*;
1011

1112
pub(in crate::build) trait EvalInto<'tcx> {
1213
fn eval_into(
1314
self,
1415
builder: &mut Builder<'_, 'tcx>,
1516
destination: Place<'tcx>,
17+
scope: Option<region::Scope>,
1618
block: BasicBlock,
1719
) -> BlockAnd<()>;
1820
}
@@ -21,13 +23,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2123
crate fn into<E>(
2224
&mut self,
2325
destination: Place<'tcx>,
26+
scope: Option<region::Scope>,
2427
block: BasicBlock,
2528
expr: E,
2629
) -> BlockAnd<()>
2730
where
2831
E: EvalInto<'tcx>,
2932
{
30-
expr.eval_into(self, destination, block)
33+
expr.eval_into(self, destination, scope, block)
3134
}
3235
}
3336

@@ -36,10 +39,11 @@ impl<'tcx> EvalInto<'tcx> for ExprRef<'tcx> {
3639
self,
3740
builder: &mut Builder<'_, 'tcx>,
3841
destination: Place<'tcx>,
42+
scope: Option<region::Scope>,
3943
block: BasicBlock,
4044
) -> BlockAnd<()> {
4145
let expr = builder.hir.mirror(self);
42-
builder.into_expr(destination, block, expr)
46+
builder.into_expr(destination, scope, block, expr)
4347
}
4448
}
4549

@@ -48,8 +52,9 @@ impl<'tcx> EvalInto<'tcx> for Expr<'tcx> {
4852
self,
4953
builder: &mut Builder<'_, 'tcx>,
5054
destination: Place<'tcx>,
55+
scope: Option<region::Scope>,
5156
block: BasicBlock,
5257
) -> BlockAnd<()> {
53-
builder.into_expr(destination, block, self)
58+
builder.into_expr(destination, scope, block, self)
5459
}
5560
}

0 commit comments

Comments
 (0)