Skip to content

Commit

Permalink
Avoid leaking values when panicking in certain cases
Browse files Browse the repository at this point in the history
  • Loading branch information
matthewjasper committed Jun 3, 2024
1 parent f9aafda commit 087332f
Show file tree
Hide file tree
Showing 21 changed files with 682 additions and 455 deletions.
19 changes: 15 additions & 4 deletions compiler/rustc_mir_build/src/build/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
pub(crate) fn ast_block(
&mut self,
destination: Place<'tcx>,
scope: Option<Scope>,
block: BasicBlock,
ast_block: BlockId,
source_info: SourceInfo,
Expand All @@ -19,18 +20,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.thir[ast_block];
self.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| {
if targeted_by_break {
this.in_breakable_scope(None, destination, span, |this| {
Some(this.ast_block_stmts(destination, block, span, stmts, expr, region_scope))
this.in_breakable_scope(None, destination, scope, span, |this| {
Some(this.ast_block_stmts(
destination,
scope,
block,
span,
stmts,
expr,
region_scope,
))
})
} else {
this.ast_block_stmts(destination, block, span, stmts, expr, region_scope)
this.ast_block_stmts(destination, scope, block, span, stmts, expr, region_scope)
}
})
}

fn ast_block_stmts(
&mut self,
destination: Place<'tcx>,
scope: Option<Scope>,
mut block: BasicBlock,
span: Span,
stmts: &[StmtId],
Expand Down Expand Up @@ -168,6 +178,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
unpack!(
failure_block = this.ast_block(
dummy_place,
None,
failure_entry,
*else_block,
this.source_info(else_block_span),
Expand Down Expand Up @@ -321,7 +332,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
this.block_context
.push(BlockFrame::TailExpr { tail_result_is_ignored, span: expr.span });

unpack!(block = this.expr_into_dest(destination, block, expr_id));
unpack!(block = this.expr_into_dest(destination, scope, block, expr_id));
let popped = this.block_context.pop();

assert!(popped.is_some_and(|bf| bf.is_tail_expr()));
Expand Down
4 changes: 3 additions & 1 deletion compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let box_ = Rvalue::ShallowInitBox(Operand::Move(storage), value_ty);
this.cfg.push_assign(block, source_info, Place::from(result), box_);

// initialize the box contents:
// Initialize the box contents. No scope is needed since the
// `Box` is already scheduled to be dropped.
unpack!(
block = this.expr_into_dest(
this.tcx.mk_place_deref(Place::from(result)),
None,
block,
value,
)
Expand Down
6 changes: 1 addition & 5 deletions compiler/rustc_mir_build/src/build/expr/as_temp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}

unpack!(block = this.expr_into_dest(temp_place, block, expr_id));

if let Some(temp_lifetime) = temp_lifetime {
this.schedule_drop(expr_span, temp_lifetime, temp, DropKind::Value);
}
unpack!(block = this.expr_into_dest(temp_place, temp_lifetime, block, expr_id));

block.and(temp)
}
Expand Down
104 changes: 73 additions & 31 deletions compiler/rustc_mir_build/src/build/expr/into.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
//! See docs in build/expr/mod.rs

use crate::build::expr::category::{Category, RvalueFunc};
use crate::build::scope::DropKind;
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, NeedsTemporary};
use rustc_ast::InlineAsmOptions;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir as hir;
use rustc_index::IndexVec;
use rustc_middle::middle::region;
use rustc_middle::mir::*;
use rustc_middle::span_bug;
use rustc_middle::thir::*;
Expand All @@ -14,13 +17,16 @@ use rustc_span::source_map::Spanned;
use std::iter;
use tracing::{debug, instrument};

use std::slice;

impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Compile `expr`, storing the result into `destination`, which
/// is assumed to be uninitialized.
#[instrument(level = "debug", skip(self))]
pub(crate) fn expr_into_dest(
&mut self,
destination: Place<'tcx>,
scope: Option<region::Scope>,
mut block: BasicBlock,
expr_id: ExprId,
) -> BlockAnd<()> {
Expand All @@ -35,6 +41,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let expr_is_block_or_scope =
matches!(expr.kind, ExprKind::Block { .. } | ExprKind::Scope { .. });

let schedule_drop = move |this: &mut Self| {
if let Some(drop_scope) = scope {
let local =
destination.as_local().expect("cannot schedule drop of non-Local place");
this.schedule_drop(expr_span, drop_scope, local, DropKind::Value);
}
};

if !expr_is_block_or_scope {
this.block_context.push(BlockFrame::SubExpr);
}
Expand All @@ -44,15 +58,16 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let region_scope = (region_scope, source_info);
ensure_sufficient_stack(|| {
this.in_scope(region_scope, lint_level, |this| {
this.expr_into_dest(destination, block, value)
this.expr_into_dest(destination, scope, block, value)
})
})
}
ExprKind::Block { block: ast_block } => {
this.ast_block(destination, block, ast_block, source_info)
this.ast_block(destination, scope, block, ast_block, source_info)
}
ExprKind::Match { scrutinee, ref arms, .. } => this.match_expr(
destination,
scope,
block,
scrutinee,
arms,
Expand Down Expand Up @@ -90,7 +105,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
));

// Lower the `then` arm into its block.
this.expr_into_dest(destination, then_blk, then)
let then_blk =
this.expr_into_dest(destination, scope, then_blk, then);
if let Some(drop_scope) = scope {
let local = destination
.as_local()
.expect("cannot unschedule drop of non-Local place");
this.unschedule_drop(drop_scope, local);
}
then_blk
});

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

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

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

this.in_breakable_scope(Some(loop_block), destination, expr_span, move |this| {
// conduct the test, if necessary
let body_block = this.cfg.start_new_block();
this.cfg.terminate(
loop_block,
source_info,
TerminatorKind::FalseUnwind {
real_target: body_block,
unwind: UnwindAction::Continue,
},
);
this.diverge_from(loop_block);

// The “return” value of the loop body must always be a unit. We therefore
// introduce a unit temporary as the destination for the loop body.
let tmp = this.get_unit_temp();
// Execute the body, branching back to the test.
let body_block_end = unpack!(this.expr_into_dest(tmp, body_block, body));
this.cfg.goto(body_block_end, source_info, loop_block);

// Loops are only exited by `break` expressions.
None
})
this.in_breakable_scope(
Some(loop_block),
destination,
scope,
expr_span,
move |this| {
// conduct the test, if necessary
let body_block = this.cfg.start_new_block();
this.cfg.terminate(
loop_block,
source_info,
TerminatorKind::FalseUnwind {
real_target: body_block,
unwind: UnwindAction::Continue,
},
);
this.diverge_from(loop_block);

// The “return” value of the loop body must always be a unit. We therefore
// introduce a unit temporary as the destination for the loop body.
let tmp = this.get_unit_temp();
// Execute the body, branching back to the test.
let body_block_end =
unpack!(this.expr_into_dest(tmp, scope, body_block, body));
this.cfg.goto(body_block_end, source_info, loop_block);
schedule_drop(this);

// Loops are only exited by `break` expressions.
None
},
)
}
ExprKind::Call { ty: _, fun, ref args, from_hir_call, fn_span } => {
let fun = unpack!(block = this.as_local_operand(block, fun));
Expand Down Expand Up @@ -280,9 +315,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// FIXME(matthewjasper): Look at this again if Polonius is
// stabilized.
this.record_operands_moved(&args);
schedule_drop(this);
success.unit()
}
ExprKind::Use { source } => this.expr_into_dest(destination, block, source),
ExprKind::Use { source } => this.expr_into_dest(destination, scope, block, source),
ExprKind::Borrow { arg, borrow_kind } => {
// We don't do this in `as_rvalue` because we use `as_place`
// for borrow expressions, so we cannot create an `RValue` that
Expand Down Expand Up @@ -345,7 +381,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {

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

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

// MIR does not natively support FRU, so for each
Expand Down Expand Up @@ -386,6 +422,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
destination,
Rvalue::Aggregate(adt, fields),
);
schedule_drop(this);
block.unit()
}
ExprKind::InlineAsm(box InlineAsmExpr {
Expand Down Expand Up @@ -464,7 +501,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
targets.push(target);

let tmp = this.get_unit_temp();
let target = unpack!(this.ast_block(tmp, target, block, source_info));
let target =
unpack!(this.ast_block(tmp, scope, target, block, source_info));
this.cfg.terminate(
target,
source_info,
Expand Down Expand Up @@ -528,6 +566,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let place = unpack!(block = this.as_place(block, expr_id));
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
this.cfg.push_assign(block, source_info, destination, rvalue);
schedule_drop(this);
block.unit()
}
ExprKind::Index { .. } | ExprKind::Deref { .. } | ExprKind::Field { .. } => {
Expand All @@ -543,6 +582,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let place = unpack!(block = this.as_place(block, expr_id));
let rvalue = Rvalue::Use(this.consume_by_copy_or_move(place));
this.cfg.push_assign(block, source_info, destination, rvalue);
schedule_drop(this);
block.unit()
}

Expand All @@ -565,6 +605,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
TerminatorKind::Yield { value, resume, resume_arg: destination, drop: None },
);
this.coroutine_drop_cleanup(block);
schedule_drop(this);
resume.unit()
}

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

let rvalue = unpack!(block = this.as_local_rvalue(block, expr_id));
this.cfg.push_assign(block, source_info, destination, rvalue);
schedule_drop(this);
block.unit()
}
};
Expand Down
Loading

0 comments on commit 087332f

Please sign in to comment.