Skip to content

Commit 8b66dc1

Browse files
committed
Rust: Fix CFG for labelled block expressions
1 parent e8cb349 commit 8b66dc1

File tree

2 files changed

+41
-6
lines changed

2 files changed

+41
-6
lines changed

rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,14 +136,40 @@ class LogicalAndBinaryOpExprTree extends PreOrderTree, LogicalAndExpr {
136136
}
137137
}
138138

139-
class BlockExprBaseTree extends StandardPostOrderTree instanceof BlockExpr {
139+
class BlockExprTree extends StandardPostOrderTree, BlockExpr {
140140
override AstNode getChildNode(int i) {
141141
result = super.getStmtList().getStatement(i)
142142
or
143143
not exists(super.getStmtList().getStatement(i)) and
144144
(exists(super.getStmtList().getStatement(i - 1)) or i = 0) and
145145
result = super.getStmtList().getTailExpr()
146146
}
147+
148+
override predicate propagatesAbnormal(AstNode child) { none() }
149+
150+
/** Holds if this block captures the break completion `c`. */
151+
private predicate capturesBreakCompletion(LoopJumpCompletion c) {
152+
c.isBreak() and
153+
c.getLabelName() = this.getLabel().getLifetime().getText()
154+
}
155+
156+
override predicate succ(AstNode pred, AstNode succ, Completion c) {
157+
super.succ(pred, succ, c)
158+
or
159+
// Edge for exiting the block with a break expressions
160+
last(this.getChildNode(_), pred, c) and
161+
this.capturesBreakCompletion(c) and
162+
succ = this
163+
}
164+
165+
override predicate last(AstNode last, Completion c) {
166+
super.last(last, c)
167+
or
168+
// Any abnormal completions that this block does not capture should propagate
169+
last(this.getChildNode(_), last, c) and
170+
not completionIsNormal(c) and
171+
not this.capturesBreakCompletion(c)
172+
}
147173
}
148174

149175
class BreakExprTree extends PostOrderTree instanceof BreakExpr {
@@ -293,7 +319,7 @@ abstract class LoopingExprTree extends PostOrderTree {
293319
abstract predicate entry(AstNode node);
294320

295321
/** Holds if this loop captures the `c` completion. */
296-
predicate capturesLoopJumpCompletion(LoopJumpCompletion c) {
322+
private predicate capturesLoopJumpCompletion(LoopJumpCompletion c) {
297323
not c.hasLabel()
298324
or
299325
c.getLabelName() = this.getLabel().getLifetime().getText()

rust/ql/test/library-tests/controlflow/Cfg.expected

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -343,11 +343,20 @@
343343
| test.rs:175:13:175:13 | 0 | test.rs:174:16:176:9 | BlockExpr | |
344344
| test.rs:179:5:187:5 | enter test_labelled_block | test.rs:181:13:181:31 | ExprStmt | |
345345
| test.rs:179:5:187:5 | exit test_labelled_block (normal) | test.rs:179:5:187:5 | exit test_labelled_block | |
346-
| test.rs:181:13:181:30 | BreakExpr | test.rs:179:5:187:5 | exit test_labelled_block (normal) | break('block) |
346+
| test.rs:179:43:187:5 | BlockExpr | test.rs:179:5:187:5 | exit test_labelled_block (normal) | |
347+
| test.rs:180:9:186:9 | IfExpr | test.rs:179:43:187:5 | BlockExpr | |
348+
| test.rs:180:12:182:10 | ParenExpr | test.rs:183:13:183:13 | 1 | true |
349+
| test.rs:180:12:182:10 | ParenExpr | test.rs:185:13:185:13 | 0 | false |
350+
| test.rs:180:13:182:9 | BlockExpr | test.rs:180:12:182:10 | ParenExpr | |
351+
| test.rs:181:13:181:30 | BreakExpr | test.rs:180:13:182:9 | BlockExpr | break('block) |
347352
| test.rs:181:13:181:31 | ExprStmt | test.rs:181:26:181:26 | a | |
348353
| test.rs:181:26:181:26 | a | test.rs:181:30:181:30 | 0 | |
349354
| test.rs:181:26:181:30 | ... > ... | test.rs:181:13:181:30 | BreakExpr | |
350355
| test.rs:181:30:181:30 | 0 | test.rs:181:26:181:30 | ... > ... | |
356+
| test.rs:182:12:184:9 | BlockExpr | test.rs:180:9:186:9 | IfExpr | |
357+
| test.rs:183:13:183:13 | 1 | test.rs:182:12:184:9 | BlockExpr | |
358+
| test.rs:184:16:186:9 | BlockExpr | test.rs:180:9:186:9 | IfExpr | |
359+
| test.rs:185:13:185:13 | 0 | test.rs:184:16:186:9 | BlockExpr | |
351360
| test.rs:192:5:195:5 | enter test_and_operator | test.rs:193:9:193:28 | LetStmt | |
352361
| test.rs:192:5:195:5 | exit test_and_operator (normal) | test.rs:192:5:195:5 | exit test_and_operator | |
353362
| test.rs:192:61:195:5 | BlockExpr | test.rs:192:5:195:5 | exit test_and_operator (normal) | |
@@ -495,7 +504,7 @@
495504
| test.rs:269:12:269:28 | PathExpr | test.rs:269:12:269:30 | CallExpr | |
496505
| test.rs:269:12:269:30 | CallExpr | test.rs:269:9:271:9 | IfExpr | false |
497506
| test.rs:269:12:269:30 | CallExpr | test.rs:270:13:270:27 | ExprStmt | true |
498-
| test.rs:270:13:270:26 | BreakExpr | test.rs:266:1:279:1 | exit labelled_block1 (normal) | break('block) |
507+
| test.rs:270:13:270:26 | BreakExpr | test.rs:267:18:278:5 | BlockExpr | break('block) |
499508
| test.rs:270:13:270:27 | ExprStmt | test.rs:270:26:270:26 | 1 | |
500509
| test.rs:270:26:270:26 | 1 | test.rs:270:13:270:26 | BreakExpr | |
501510
| test.rs:272:9:272:21 | PathExpr | test.rs:272:9:272:23 | CallExpr | |
@@ -506,7 +515,7 @@
506515
| test.rs:273:12:273:28 | PathExpr | test.rs:273:12:273:30 | CallExpr | |
507516
| test.rs:273:12:273:30 | CallExpr | test.rs:273:9:275:9 | IfExpr | false |
508517
| test.rs:273:12:273:30 | CallExpr | test.rs:274:13:274:27 | ExprStmt | true |
509-
| test.rs:274:13:274:26 | BreakExpr | test.rs:266:1:279:1 | exit labelled_block1 (normal) | break('block) |
518+
| test.rs:274:13:274:26 | BreakExpr | test.rs:267:18:278:5 | BlockExpr | break('block) |
510519
| test.rs:274:13:274:27 | ExprStmt | test.rs:274:26:274:26 | 2 | |
511520
| test.rs:274:26:274:26 | 2 | test.rs:274:13:274:26 | BreakExpr | |
512521
| test.rs:276:9:276:21 | PathExpr | test.rs:276:9:276:23 | CallExpr | |
@@ -526,7 +535,7 @@
526535
| test.rs:284:13:284:19 | TupleStructPat | test.rs:285:13:285:27 | ExprStmt | no-match |
527536
| test.rs:284:13:284:19 | TupleStructPat | test.rs:287:9:287:9 | x | match |
528537
| test.rs:284:23:284:23 | x | test.rs:284:13:284:19 | TupleStructPat | |
529-
| test.rs:285:13:285:26 | BreakExpr | test.rs:281:1:289:1 | exit labelled_block2 (normal) | break('block) |
538+
| test.rs:285:13:285:26 | BreakExpr | test.rs:282:18:288:5 | BlockExpr | break('block) |
530539
| test.rs:285:13:285:27 | ExprStmt | test.rs:285:26:285:26 | 1 | |
531540
| test.rs:285:26:285:26 | 1 | test.rs:285:13:285:26 | BreakExpr | |
532541
| test.rs:287:9:287:9 | x | test.rs:282:18:288:5 | BlockExpr | |

0 commit comments

Comments
 (0)