Skip to content

Commit 28ac9be

Browse files
committed
Avoid leaking values when panicking in certain cases
1 parent f2b8005 commit 28ac9be

21 files changed

+683
-455
lines changed

compiler/rustc_mir_build/src/build/block.rs

+15-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1111
pub(crate) fn ast_block(
1212
&mut self,
1313
destination: Place<'tcx>,
14+
scope: Option<Scope>,
1415
block: BasicBlock,
1516
ast_block: BlockId,
1617
source_info: SourceInfo,
@@ -19,18 +20,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1920
self.thir[ast_block];
2021
self.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
2122
if targeted_by_break {
22-
this.in_breakable_scope(None, destination, span, |this| {
23-
Some(this.ast_block_stmts(destination, block, span, stmts, expr, region_scope))
23+
this.in_breakable_scope(None, destination, scope, span, |this| {
24+
Some(this.ast_block_stmts(
25+
destination,
26+
scope,
27+
block,
28+
span,
29+
stmts,
30+
expr,
31+
region_scope,
32+
))
2433
})
2534
} else {
26-
this.ast_block_stmts(destination, block, span, stmts, expr, region_scope)
35+
this.ast_block_stmts(destination, scope, block, span, stmts, expr, region_scope)
2736
}
2837
})
2938
}
3039

3140
fn ast_block_stmts(
3241
&mut self,
3342
destination: Place<'tcx>,
43+
scope: Option<Scope>,
3444
mut block: BasicBlock,
3545
span: Span,
3646
stmts: &[StmtId],
@@ -168,6 +178,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
168178
unpack!(
169179
failure_block = this.ast_block(
170180
dummy_place,
181+
None,
171182
failure_entry,
172183
*else_block,
173184
this.source_info(else_block_span),
@@ -321,7 +332,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
321332
this.block_context
322333
.push(BlockFrame::TailExpr { tail_result_is_ignored, span: expr.span });
323334

324-
unpack!(block = this.expr_into_dest(destination, block, expr_id));
335+
unpack!(block = this.expr_into_dest(destination, scope, block, expr_id));
325336
let popped = this.block_context.pop();
326337

327338
assert!(popped.is_some_and(|bf| bf.is_tail_expr()));

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

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

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

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
@@ -1,11 +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, NeedsTemporary};
56
use rustc_ast::InlineAsmOptions;
67
use rustc_data_structures::fx::FxHashMap;
78
use rustc_data_structures::stack::ensure_sufficient_stack;
89
use rustc_hir as hir;
10+
use rustc_index::IndexVec;
11+
use rustc_middle::middle::region;
912
use rustc_middle::mir::*;
1013
use rustc_middle::span_bug;
1114
use rustc_middle::thir::*;
@@ -14,13 +17,16 @@ use rustc_span::source_map::Spanned;
1417
use std::iter;
1518
use tracing::{debug, instrument};
1619

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

44+
let schedule_drop = move |this: &mut Self| {
45+
if let Some(drop_scope) = scope {
46+
let local =
47+
destination.as_local().expect("cannot schedule drop of non-Local place");
48+
this.schedule_drop(expr_span, drop_scope, local, DropKind::Value);
49+
}
50+
};
51+
3852
if !expr_is_block_or_scope {
3953
this.block_context.push(BlockFrame::SubExpr);
4054
}
@@ -44,15 +58,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
4458
let region_scope = (region_scope, source_info);
4559
ensure_sufficient_stack(|| {
4660
this.in_scope(region_scope, lint_level, |this| {
47-
this.expr_into_dest(destination, block, value)
61+
this.expr_into_dest(destination, scope, block, value)
4862
})
4963
})
5064
}
5165
ExprKind::Block { block: ast_block } => {
52-
this.ast_block(destination, block, ast_block, source_info)
66+
this.ast_block(destination, scope, block, ast_block, source_info)
5367
}
5468
ExprKind::Match { scrutinee, ref arms, .. } => this.match_expr(
5569
destination,
70+
scope,
5671
block,
5772
scrutinee,
5873
arms,
@@ -90,7 +105,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
90105
));
91106

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

96119
// Pack `(then_block, else_block)` into `BlockAnd<BasicBlock>`.
@@ -104,7 +127,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
104127

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

140165
// This is an optimization. If the expression was a call then we already have an
141166
// unreachable block. Don't bother to terminate it and create a new one.
167+
schedule_drop(this);
142168
if is_call {
143169
block.unit()
144170
} else {
@@ -183,7 +209,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
183209
const_: Const::from_bool(this.tcx, constant),
184210
},
185211
);
186-
let mut rhs_block = unpack!(this.expr_into_dest(destination, continuation, rhs));
212+
let mut rhs_block =
213+
unpack!(this.expr_into_dest(destination, scope, continuation, rhs));
187214
// Instrument the lowered RHS's value for condition coverage.
188215
// (Does nothing if condition coverage is not enabled.)
189216
this.visit_coverage_standalone_condition(rhs, destination, &mut rhs_block);
@@ -209,29 +236,37 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
209236
// Start the loop.
210237
this.cfg.goto(block, source_info, loop_block);
211238

212-
this.in_breakable_scope(Some(loop_block), destination, expr_span, move |this| {
213-
// conduct the test, if necessary
214-
let body_block = this.cfg.start_new_block();
215-
this.cfg.terminate(
216-
loop_block,
217-
source_info,
218-
TerminatorKind::FalseUnwind {
219-
real_target: body_block,
220-
unwind: UnwindAction::Continue,
221-
},
222-
);
223-
this.diverge_from(loop_block);
224-
225-
// The “return” value of the loop body must always be a unit. We therefore
226-
// introduce a unit temporary as the destination for the loop body.
227-
let tmp = this.get_unit_temp();
228-
// Execute the body, branching back to the test.
229-
let body_block_end = unpack!(this.expr_into_dest(tmp, body_block, body));
230-
this.cfg.goto(body_block_end, source_info, loop_block);
231-
232-
// Loops are only exited by `break` expressions.
233-
None
234-
})
239+
this.in_breakable_scope(
240+
Some(loop_block),
241+
destination,
242+
scope,
243+
expr_span,
244+
move |this| {
245+
// conduct the test, if necessary
246+
let body_block = this.cfg.start_new_block();
247+
this.cfg.terminate(
248+
loop_block,
249+
source_info,
250+
TerminatorKind::FalseUnwind {
251+
real_target: body_block,
252+
unwind: UnwindAction::Continue,
253+
},
254+
);
255+
this.diverge_from(loop_block);
256+
257+
// The “return” value of the loop body must always be a unit. We therefore
258+
// introduce a unit temporary as the destination for the loop body.
259+
let tmp = this.get_unit_temp();
260+
// Execute the body, branching back to the test.
261+
let body_block_end =
262+
unpack!(this.expr_into_dest(tmp, scope, body_block, body));
263+
this.cfg.goto(body_block_end, source_info, loop_block);
264+
schedule_drop(this);
265+
266+
// Loops are only exited by `break` expressions.
267+
None
268+
},
269+
)
235270
}
236271
ExprKind::Call { ty: _, fun, ref args, from_hir_call, fn_span } => {
237272
let fun = unpack!(block = this.as_local_operand(block, fun));
@@ -280,9 +315,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
280315
// FIXME(matthewjasper): Look at this again if Polonius is
281316
// stabilized.
282317
this.record_operands_moved(&args);
318+
schedule_drop(this);
283319
success.unit()
284320
}
285-
ExprKind::Use { source } => this.expr_into_dest(destination, block, source),
321+
ExprKind::Use { source } => this.expr_into_dest(destination, scope, block, source),
286322
ExprKind::Borrow { arg, borrow_kind } => {
287323
// We don't do this in `as_rvalue` because we use `as_place`
288324
// for borrow expressions, so we cannot create an `RValue` that
@@ -345,7 +381,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
345381

346382
let field_names = adt_def.variant(variant_index).fields.indices();
347383

348-
let fields = if let Some(FruInfo { base, field_types }) = base {
384+
let fields: IndexVec<_, _> = if let Some(FruInfo { base, field_types }) = base {
349385
let place_builder = unpack!(block = this.as_place_builder(block, *base));
350386

351387
// MIR does not natively support FRU, so for each
@@ -386,6 +422,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
386422
destination,
387423
Rvalue::Aggregate(adt, fields),
388424
);
425+
schedule_drop(this);
389426
block.unit()
390427
}
391428
ExprKind::InlineAsm(box InlineAsmExpr {
@@ -464,7 +501,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
464501
targets.push(target);
465502

466503
let tmp = this.get_unit_temp();
467-
let target = unpack!(this.ast_block(tmp, target, block, source_info));
504+
let target =
505+
unpack!(this.ast_block(tmp, scope, target, block, source_info));
468506
this.cfg.terminate(
469507
target,
470508
source_info,
@@ -528,6 +566,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
528566
let place = unpack!(block = this.as_place(block, expr_id));
529567
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
530568
this.cfg.push_assign(block, source_info, destination, rvalue);
569+
schedule_drop(this);
531570
block.unit()
532571
}
533572
ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Field { .. } => {
@@ -543,6 +582,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
543582
let place = unpack!(block = this.as_place(block, expr_id));
544583
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
545584
this.cfg.push_assign(block, source_info, destination, rvalue);
585+
schedule_drop(this);
546586
block.unit()
547587
}
548588

@@ -565,6 +605,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
565605
TerminatorKind::Yield { value, resume, resume_arg: destination, drop: None },
566606
);
567607
this.coroutine_drop_cleanup(block);
608+
schedule_drop(this);
568609
resume.unit()
569610
}
570611

@@ -601,6 +642,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
601642

602643
let rvalue = unpack!(block = this.as_local_rvalue(block, expr_id));
603644
this.cfg.push_assign(block, source_info, destination, rvalue);
645+
schedule_drop(this);
604646
block.unit()
605647
}
606648
};

0 commit comments

Comments
 (0)