Skip to content

Commit 23c13aa

Browse files
committed
Avoid leaking values when panicking in certain cases
1 parent 21a3b39 commit 23c13aa

22 files changed

+714
-455
lines changed

compiler/rustc_mir_build/src/build/block.rs

+20-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::build::matches::{DeclareLetBindings, EmitStorageLive, ScheduleDrops};
2+
use crate::build::scope::DropKind;
23
use crate::build::ForGuard::OutsideGuard;
34
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
45
use rustc_middle::middle::region::Scope;
@@ -12,6 +13,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1213
pub(crate) fn ast_block(
1314
&mut self,
1415
destination: Place<'tcx>,
16+
scope: Option<Scope>,
1517
block: BasicBlock,
1618
ast_block: BlockId,
1719
source_info: SourceInfo,
@@ -20,18 +22,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
2022
self.thir[ast_block];
2123
self.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
2224
if targeted_by_break {
23-
this.in_breakable_scope(None, destination, span, |this| {
24-
Some(this.ast_block_stmts(destination, block, span, stmts, expr, region_scope))
25+
this.in_breakable_scope(None, destination, scope, span, |this| {
26+
Some(this.ast_block_stmts(
27+
destination,
28+
scope,
29+
block,
30+
span,
31+
stmts,
32+
expr,
33+
region_scope,
34+
))
2535
})
2636
} else {
27-
this.ast_block_stmts(destination, block, span, stmts, expr, region_scope)
37+
this.ast_block_stmts(destination, scope, block, span, stmts, expr, region_scope)
2838
}
2939
})
3040
}
3141

3242
fn ast_block_stmts(
3343
&mut self,
3444
destination: Place<'tcx>,
45+
scope: Option<Scope>,
3546
mut block: BasicBlock,
3647
span: Span,
3748
stmts: &[StmtId],
@@ -169,6 +180,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
169180
unpack!(
170181
failure_block = this.ast_block(
171182
dummy_place,
183+
None,
172184
failure_entry,
173185
*else_block,
174186
this.source_info(else_block_span),
@@ -333,7 +345,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
333345
this.block_context
334346
.push(BlockFrame::TailExpr { tail_result_is_ignored, span: expr.span });
335347

336-
unpack!(block = this.expr_into_dest(destination, block, expr_id));
348+
unpack!(block = this.expr_into_dest(destination, scope, block, expr_id));
337349
let popped = this.block_context.pop();
338350

339351
assert!(popped.is_some_and(|bf| bf.is_tail_expr()));
@@ -350,6 +362,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
350362
// We only want to assign an implicit `()` as the return value of the block if the
351363
// block does not diverge. (Otherwise, we may try to assign a unit to a `!`-type.)
352364
this.cfg.push_assign_unit(block, source_info, destination, this.tcx);
365+
} else if let Some(destination_local) = destination.as_local()
366+
&& let Some(scope) = scope
367+
{
368+
this.schedule_drop(span, scope, destination_local, DropKind::Value);
353369
}
354370
}
355371
// Finally, we pop all the let scopes before exiting out from the scope of block

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
186186
let box_ = Rvalue::ShallowInitBox(Operand::Move(storage), value_ty);
187187
this.cfg.push_assign(block, source_info, Place::from(result), box_);
188188

189-
// initialize the box contents:
189+
// Initialize the box contents. No scope is needed since the
190+
// `Box` is already scheduled to be dropped.
190191
unpack!(
191192
block = this.expr_into_dest(
192193
this.tcx.mk_place_deref(Place::from(result)),
194+
None,
193195
block,
194196
value,
195197
)

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

+1-5
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
112112
}
113113
}
114114

115-
unpack!(block = this.expr_into_dest(temp_place, block, expr_id));
116-
117-
if let Some(temp_lifetime) = temp_lifetime {
118-
this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value);
119-
}
115+
unpack!(block = this.expr_into_dest(temp_place, temp_lifetime, block, expr_id));
120116

121117
block.and(temp)
122118
}

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

+73-31
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,14 @@
22
33
use crate::build::expr::category::{Category, RvalueFunc};
44
use crate::build::matches::DeclareLetBindings;
5+
use crate::build::scope::DropKind;
56
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, NeedsTemporary};
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_index::IndexVec;
12+
use rustc_middle::middle::region;
1013
use rustc_middle::mir::*;
1114
use rustc_middle::span_bug;
1215
use rustc_middle::thir::*;
@@ -15,13 +18,16 @@ use rustc_span::source_map::Spanned;
1518
use std::iter;
1619
use tracing::{debug, instrument};
1720

21+
use std::slice;
22+
1823
impl<'a, 'tcx> Builder<'a, 'tcx> {
1924
/// Compile `expr`, storing the result into `destination`, which
2025
/// is assumed to be uninitialized.
2126
#[instrument(level = "debug", skip(self))]
2227
pub(crate) fn expr_into_dest(
2328
&mut self,
2429
destination: Place<'tcx>,
30+
scope: Option<region::Scope>,
2531
mut block: BasicBlock,
2632
expr_id: ExprId,
2733
) -> BlockAnd<()> {
@@ -36,6 +42,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3642
let expr_is_block_or_scope =
3743
matches!(expr.kind, ExprKind::Block { .. } | ExprKind::Scope { .. });
3844

45+
let schedule_drop = move |this: &mut Self| {
46+
if let Some(drop_scope) = scope {
47+
let local =
48+
destination.as_local().expect("cannot schedule drop of non-Local place");
49+
this.schedule_drop(expr_span, drop_scope, local, DropKind::Value);
50+
}
51+
};
52+
3953
if !expr_is_block_or_scope {
4054
this.block_context.push(BlockFrame::SubExpr);
4155
}
@@ -45,15 +59,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
4559
let region_scope = (region_scope, source_info);
4660
ensure_sufficient_stack(|| {
4761
this.in_scope(region_scope, lint_level, |this| {
48-
this.expr_into_dest(destination, block, value)
62+
this.expr_into_dest(destination, scope, block, value)
4963
})
5064
})
5165
}
5266
ExprKind::Block { block: ast_block } => {
53-
this.ast_block(destination, block, ast_block, source_info)
67+
this.ast_block(destination, scope, block, ast_block, source_info)
5468
}
5569
ExprKind::Match { scrutinee, ref arms, .. } => this.match_expr(
5670
destination,
71+
scope,
5772
block,
5873
scrutinee,
5974
arms,
@@ -91,7 +106,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
91106
));
92107

93108
// Lower the `then` arm into its block.
94-
this.expr_into_dest(destination, then_blk, then)
109+
let then_blk =
110+
this.expr_into_dest(destination, scope, then_blk, then);
111+
if let Some(drop_scope) = scope {
112+
let local = destination
113+
.as_local()
114+
.expect("cannot unschedule drop of non-Local place");
115+
this.unschedule_drop(drop_scope, local);
116+
}
117+
then_blk
95118
});
96119

97120
// Pack `(then_block, else_block)` into `BlockAnd<BasicBlock>`.
@@ -105,7 +128,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
105128

106129
// If there is an `else` arm, lower it into `else_blk`.
107130
if let Some(else_expr) = else_opt {
108-
unpack!(else_blk = this.expr_into_dest(destination, else_blk, else_expr));
131+
unpack!(
132+
else_blk = this.expr_into_dest(destination, scope, else_blk, else_expr)
133+
);
109134
} else {
110135
// There is no `else` arm, so we know both arms have type `()`.
111136
// Generate the implicit `else {}` by assigning unit.
@@ -140,6 +165,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
140165

141166
// This is an optimization. If the expression was a call then we already have an
142167
// unreachable block. Don't bother to terminate it and create a new one.
168+
schedule_drop(this);
143169
if is_call {
144170
block.unit()
145171
} else {
@@ -187,7 +213,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
187213
const_: Const::from_bool(this.tcx, constant),
188214
},
189215
);
190-
let mut rhs_block = unpack!(this.expr_into_dest(destination, continuation, rhs));
216+
let mut rhs_block =
217+
unpack!(this.expr_into_dest(destination, scope, continuation, rhs));
191218
// Instrument the lowered RHS's value for condition coverage.
192219
// (Does nothing if condition coverage is not enabled.)
193220
this.visit_coverage_standalone_condition(rhs, destination, &mut rhs_block);
@@ -213,29 +240,37 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
213240
// Start the loop.
214241
this.cfg.goto(block, source_info, loop_block);
215242

216-
this.in_breakable_scope(Some(loop_block), destination, expr_span, move |this| {
217-
// conduct the test, if necessary
218-
let body_block = this.cfg.start_new_block();
219-
this.cfg.terminate(
220-
loop_block,
221-
source_info,
222-
TerminatorKind::FalseUnwind {
223-
real_target: body_block,
224-
unwind: UnwindAction::Continue,
225-
},
226-
);
227-
this.diverge_from(loop_block);
228-
229-
// The “return” value of the loop body must always be a unit. We therefore
230-
// introduce a unit temporary as the destination for the loop body.
231-
let tmp = this.get_unit_temp();
232-
// Execute the body, branching back to the test.
233-
let body_block_end = unpack!(this.expr_into_dest(tmp, body_block, body));
234-
this.cfg.goto(body_block_end, source_info, loop_block);
235-
236-
// Loops are only exited by `break` expressions.
237-
None
238-
})
243+
this.in_breakable_scope(
244+
Some(loop_block),
245+
destination,
246+
scope,
247+
expr_span,
248+
move |this| {
249+
// conduct the test, if necessary
250+
let body_block = this.cfg.start_new_block();
251+
this.cfg.terminate(
252+
loop_block,
253+
source_info,
254+
TerminatorKind::FalseUnwind {
255+
real_target: body_block,
256+
unwind: UnwindAction::Continue,
257+
},
258+
);
259+
this.diverge_from(loop_block);
260+
261+
// The “return” value of the loop body must always be a unit. We therefore
262+
// introduce a unit temporary as the destination for the loop body.
263+
let tmp = this.get_unit_temp();
264+
// Execute the body, branching back to the test.
265+
let body_block_end =
266+
unpack!(this.expr_into_dest(tmp, scope, body_block, body));
267+
this.cfg.goto(body_block_end, source_info, loop_block);
268+
schedule_drop(this);
269+
270+
// Loops are only exited by `break` expressions.
271+
None
272+
},
273+
)
239274
}
240275
ExprKind::Call { ty: _, fun, ref args, from_hir_call, fn_span } => {
241276
let fun = unpack!(block = this.as_local_operand(block, fun));
@@ -284,9 +319,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
284319
// FIXME(matthewjasper): Look at this again if Polonius is
285320
// stabilized.
286321
this.record_operands_moved(&args);
322+
schedule_drop(this);
287323
success.unit()
288324
}
289-
ExprKind::Use { source } => this.expr_into_dest(destination, block, source),
325+
ExprKind::Use { source } => this.expr_into_dest(destination, scope, block, source),
290326
ExprKind::Borrow { arg, borrow_kind } => {
291327
// We don't do this in `as_rvalue` because we use `as_place`
292328
// for borrow expressions, so we cannot create an `RValue` that
@@ -349,7 +385,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
349385

350386
let field_names = adt_def.variant(variant_index).fields.indices();
351387

352-
let fields = if let Some(FruInfo { base, field_types }) = base {
388+
let fields: IndexVec<_, _> = if let Some(FruInfo { base, field_types }) = base {
353389
let place_builder = unpack!(block = this.as_place_builder(block, *base));
354390

355391
// MIR does not natively support FRU, so for each
@@ -390,6 +426,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
390426
destination,
391427
Rvalue::Aggregate(adt, fields),
392428
);
429+
schedule_drop(this);
393430
block.unit()
394431
}
395432
ExprKind::InlineAsm(box InlineAsmExpr {
@@ -468,7 +505,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
468505
targets.push(target);
469506

470507
let tmp = this.get_unit_temp();
471-
let target = unpack!(this.ast_block(tmp, target, block, source_info));
508+
let target =
509+
unpack!(this.ast_block(tmp, scope, target, block, source_info));
472510
this.cfg.terminate(
473511
target,
474512
source_info,
@@ -532,6 +570,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
532570
let place = unpack!(block = this.as_place(block, expr_id));
533571
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
534572
this.cfg.push_assign(block, source_info, destination, rvalue);
573+
schedule_drop(this);
535574
block.unit()
536575
}
537576
ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Field { .. } => {
@@ -547,6 +586,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
547586
let place = unpack!(block = this.as_place(block, expr_id));
548587
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
549588
this.cfg.push_assign(block, source_info, destination, rvalue);
589+
schedule_drop(this);
550590
block.unit()
551591
}
552592

@@ -569,6 +609,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
569609
TerminatorKind::Yield { value, resume, resume_arg: destination, drop: None },
570610
);
571611
this.coroutine_drop_cleanup(block);
612+
schedule_drop(this);
572613
resume.unit()
573614
}
574615

@@ -605,6 +646,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
605646

606647
let rvalue = unpack!(block = this.as_local_rvalue(block, expr_id));
607648
this.cfg.push_assign(block, source_info, destination, rvalue);
649+
schedule_drop(this);
608650
block.unit()
609651
}
610652
};

0 commit comments

Comments
 (0)