Skip to content

Commit 3aedfbe

Browse files
committed
Enforce unwind invariants
1 parent 7355816 commit 3aedfbe

File tree

1 file changed

+41
-19
lines changed

1 file changed

+41
-19
lines changed

src/librustc_mir/transform/validate.rs

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ use rustc_middle::{
1111
};
1212
use rustc_span::def_id::DefId;
1313

14+
enum EdgeKind {
15+
Unwind,
16+
Other,
17+
}
18+
1419
pub struct Validator {
1520
/// Describes at which point in the pipeline this validation is happening.
1621
pub when: String,
@@ -49,8 +54,25 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
4954
);
5055
}
5156

52-
fn check_bb(&self, location: Location, bb: BasicBlock) {
53-
if self.body.basic_blocks().get(bb).is_none() {
57+
fn check_bb(&self, location: Location, bb: BasicBlock, edge_kind: EdgeKind) {
58+
if let Some(bb) = self.body.basic_blocks().get(bb) {
59+
let src = self.body.basic_blocks().get(location.block).unwrap();
60+
match (src.is_cleanup, bb.is_cleanup, edge_kind) {
61+
// Non-cleanup blocks can jump to non-cleanup blocks along non-unwind edges
62+
(false, false, EdgeKind::Other)
63+
// Non-cleanup blocks can jump to cleanup blocks along unwind edges
64+
| (false, true, EdgeKind::Unwind)
65+
// Cleanup blocks can jump to cleanup blocks along unwind edges
66+
| (true, true, EdgeKind::Unwind) => {}
67+
// All other jumps are invalid
68+
_ => {
69+
self.fail(
70+
location,
71+
format!("encountered jump that does not respect unwind invariants {:?}", bb)
72+
)
73+
}
74+
}
75+
} else {
5476
self.fail(location, format!("encountered jump to invalid basic block {:?}", bb))
5577
}
5678
}
@@ -92,7 +114,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
92114
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
93115
match &terminator.kind {
94116
TerminatorKind::Goto { target } => {
95-
self.check_bb(location, *target);
117+
self.check_bb(location, *target, EdgeKind::Other);
96118
}
97119
TerminatorKind::SwitchInt { targets, values, .. } => {
98120
if targets.len() != values.len() + 1 {
@@ -106,19 +128,19 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
106128
);
107129
}
108130
for target in targets {
109-
self.check_bb(location, *target);
131+
self.check_bb(location, *target, EdgeKind::Other);
110132
}
111133
}
112134
TerminatorKind::Drop { target, unwind, .. } => {
113-
self.check_bb(location, *target);
135+
self.check_bb(location, *target, EdgeKind::Other);
114136
if let Some(unwind) = unwind {
115-
self.check_bb(location, *unwind);
137+
self.check_bb(location, *unwind, EdgeKind::Unwind);
116138
}
117139
}
118140
TerminatorKind::DropAndReplace { target, unwind, .. } => {
119-
self.check_bb(location, *target);
141+
self.check_bb(location, *target, EdgeKind::Other);
120142
if let Some(unwind) = unwind {
121-
self.check_bb(location, *unwind);
143+
self.check_bb(location, *unwind, EdgeKind::Unwind);
122144
}
123145
}
124146
TerminatorKind::Call { func, destination, cleanup, .. } => {
@@ -131,10 +153,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
131153
),
132154
}
133155
if let Some((_, target)) = destination {
134-
self.check_bb(location, *target);
156+
self.check_bb(location, *target, EdgeKind::Other);
135157
}
136158
if let Some(cleanup) = cleanup {
137-
self.check_bb(location, *cleanup);
159+
self.check_bb(location, *cleanup, EdgeKind::Unwind);
138160
}
139161
}
140162
TerminatorKind::Assert { cond, target, cleanup, .. } => {
@@ -148,30 +170,30 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
148170
),
149171
);
150172
}
151-
self.check_bb(location, *target);
173+
self.check_bb(location, *target, EdgeKind::Other);
152174
if let Some(cleanup) = cleanup {
153-
self.check_bb(location, *cleanup);
175+
self.check_bb(location, *cleanup, EdgeKind::Unwind);
154176
}
155177
}
156178
TerminatorKind::Yield { resume, drop, .. } => {
157-
self.check_bb(location, *resume);
179+
self.check_bb(location, *resume, EdgeKind::Other);
158180
if let Some(drop) = drop {
159-
self.check_bb(location, *drop);
181+
self.check_bb(location, *drop, EdgeKind::Other);
160182
}
161183
}
162184
TerminatorKind::FalseEdge { real_target, imaginary_target } => {
163-
self.check_bb(location, *real_target);
164-
self.check_bb(location, *imaginary_target);
185+
self.check_bb(location, *real_target, EdgeKind::Other);
186+
self.check_bb(location, *imaginary_target, EdgeKind::Other);
165187
}
166188
TerminatorKind::FalseUnwind { real_target, unwind } => {
167-
self.check_bb(location, *real_target);
189+
self.check_bb(location, *real_target, EdgeKind::Other);
168190
if let Some(unwind) = unwind {
169-
self.check_bb(location, *unwind);
191+
self.check_bb(location, *unwind, EdgeKind::Unwind);
170192
}
171193
}
172194
TerminatorKind::InlineAsm { destination, .. } => {
173195
if let Some(destination) = destination {
174-
self.check_bb(location, *destination);
196+
self.check_bb(location, *destination, EdgeKind::Other);
175197
}
176198
}
177199
// Nothing to validate for these.

0 commit comments

Comments
 (0)