Skip to content

Commit 5707838

Browse files
committed
validate basic sanity for TerminatorKind
1 parent 91fb72a commit 5707838

File tree

2 files changed

+108
-3
lines changed

2 files changed

+108
-3
lines changed

src/librustc_mir/interpret/terminator.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
5050
self.go_to_block(target_block);
5151
}
5252

53-
Call { ref func, ref args, destination, ref cleanup, .. } => {
53+
Call {
54+
ref func,
55+
ref args,
56+
destination,
57+
ref cleanup,
58+
from_hir_call: _from_hir_call,
59+
} => {
5460
let old_stack = self.frame_idx();
5561
let old_loc = self.frame().loc;
5662
let func = self.eval_operand(func, None)?;

src/librustc_mir/transform/validate.rs

+101-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
use super::{MirPass, MirSource};
44
use rustc_middle::mir::visit::Visitor;
55
use rustc_middle::{
6-
mir::{Body, Location, Operand, Rvalue, Statement, StatementKind},
7-
ty::{ParamEnv, TyCtxt},
6+
mir::{
7+
BasicBlock, Body, Location, Operand, Rvalue, Statement, StatementKind, Terminator,
8+
TerminatorKind,
9+
},
10+
ty::{self, ParamEnv, TyCtxt},
811
};
912
use rustc_span::{def_id::DefId, Span, DUMMY_SP};
1013

@@ -38,6 +41,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
3841
&format!("broken MIR in {:?} ({}): {}", self.def_id, self.when, msg.as_ref()),
3942
);
4043
}
44+
45+
fn check_bb(&self, span: Span, bb: BasicBlock) {
46+
if self.body.basic_blocks().get(bb).is_none() {
47+
self.fail(span, format!("encountered jump to invalid basic block {:?}", bb))
48+
}
49+
}
4150
}
4251

4352
impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
@@ -77,4 +86,94 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
7786
}
7887
}
7988
}
89+
90+
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, _location: Location) {
91+
match &terminator.kind {
92+
TerminatorKind::Goto { target } => {
93+
self.check_bb(terminator.source_info.span, *target);
94+
}
95+
TerminatorKind::SwitchInt { targets, .. } => {
96+
if targets.is_empty() {
97+
self.fail(
98+
terminator.source_info.span,
99+
"encountered `SwitchInt` terminator with no target to jump to",
100+
);
101+
}
102+
for target in targets {
103+
self.check_bb(terminator.source_info.span, *target);
104+
}
105+
}
106+
TerminatorKind::Drop { target, unwind, .. } => {
107+
self.check_bb(terminator.source_info.span, *target);
108+
if let Some(unwind) = unwind {
109+
self.check_bb(terminator.source_info.span, *unwind);
110+
}
111+
}
112+
TerminatorKind::DropAndReplace { target, unwind, .. } => {
113+
self.check_bb(terminator.source_info.span, *target);
114+
if let Some(unwind) = unwind {
115+
self.check_bb(terminator.source_info.span, *unwind);
116+
}
117+
}
118+
TerminatorKind::Call { func, destination, cleanup, .. } => {
119+
let func_ty = func.ty(&self.body.local_decls, self.tcx);
120+
match func_ty.kind {
121+
ty::FnPtr(..) | ty::FnDef(..) => {}
122+
_ => self.fail(
123+
terminator.source_info.span,
124+
format!("encountered non-callable type {} in `Call` terminator", func_ty),
125+
),
126+
}
127+
if let Some((_, target)) = destination {
128+
self.check_bb(terminator.source_info.span, *target);
129+
}
130+
if let Some(cleanup) = cleanup {
131+
self.check_bb(terminator.source_info.span, *cleanup);
132+
}
133+
}
134+
TerminatorKind::Assert { cond, target, cleanup, .. } => {
135+
let cond_ty = cond.ty(&self.body.local_decls, self.tcx);
136+
if cond_ty != self.tcx.types.bool {
137+
self.fail(
138+
terminator.source_info.span,
139+
format!(
140+
"encountered non-boolean condition of type {} in `Assert` terminator",
141+
cond_ty
142+
),
143+
);
144+
}
145+
self.check_bb(terminator.source_info.span, *target);
146+
if let Some(cleanup) = cleanup {
147+
self.check_bb(terminator.source_info.span, *cleanup);
148+
}
149+
}
150+
TerminatorKind::Yield { resume, drop, .. } => {
151+
self.check_bb(terminator.source_info.span, *resume);
152+
if let Some(drop) = drop {
153+
self.check_bb(terminator.source_info.span, *drop);
154+
}
155+
}
156+
TerminatorKind::FalseEdges { real_target, imaginary_target } => {
157+
self.check_bb(terminator.source_info.span, *real_target);
158+
self.check_bb(terminator.source_info.span, *imaginary_target);
159+
}
160+
TerminatorKind::FalseUnwind { real_target, unwind } => {
161+
self.check_bb(terminator.source_info.span, *real_target);
162+
if let Some(unwind) = unwind {
163+
self.check_bb(terminator.source_info.span, *unwind);
164+
}
165+
}
166+
TerminatorKind::InlineAsm { destination, .. } => {
167+
if let Some(destination) = destination {
168+
self.check_bb(terminator.source_info.span, *destination);
169+
}
170+
}
171+
// Nothing to validate for these.
172+
TerminatorKind::Resume
173+
| TerminatorKind::Abort
174+
| TerminatorKind::Return
175+
| TerminatorKind::Unreachable
176+
| TerminatorKind::GeneratorDrop => {}
177+
}
178+
}
80179
}

0 commit comments

Comments
 (0)