Skip to content

Commit 8c1fd8f

Browse files
committed
Rust: Implement CFG for ForExprs
1 parent f3e3734 commit 8c1fd8f

File tree

3 files changed

+62
-4
lines changed

3 files changed

+62
-4
lines changed

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

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,9 @@ abstract class LoopingExprTree extends PostOrderTree {
284284

285285
abstract Label getLabel();
286286

287-
/** Whether this loop captures the `c` completion. */
287+
abstract predicate entry(AstNode node);
288+
289+
/** Holds if this loop captures the `c` completion. */
288290
predicate capturesLoopJumpCompletion(LoopJumpCompletion c) {
289291
not c.hasLabel()
290292
or
@@ -305,7 +307,7 @@ abstract class LoopingExprTree extends PostOrderTree {
305307
or
306308
c.(LoopJumpCompletion).isContinue() and this.capturesLoopJumpCompletion(c)
307309
) and
308-
this.first(succ)
310+
this.entry(succ)
309311
}
310312

311313
override predicate last(AstNode last, Completion c) {
@@ -323,6 +325,8 @@ class LoopExprTree extends LoopingExprTree instanceof LoopExpr {
323325

324326
override Label getLabel() { result = LoopExpr.super.getLabel() }
325327

328+
override predicate entry(AstNode node) { this.first(node) }
329+
326330
override predicate first(AstNode node) { first(this.getLoopBody(), node) }
327331
}
328332

@@ -331,6 +335,8 @@ class WhileExprTree extends LoopingExprTree instanceof WhileExpr {
331335

332336
override Label getLabel() { result = WhileExpr.super.getLabel() }
333337

338+
override predicate entry(AstNode node) { this.first(node) }
339+
334340
override predicate first(AstNode node) { first(super.getCondition(), node) }
335341

336342
override predicate succ(AstNode pred, AstNode succ, Completion c) {
@@ -353,6 +359,39 @@ class WhileExprTree extends LoopingExprTree instanceof WhileExpr {
353359
}
354360
}
355361

362+
class ForExprTree extends LoopingExprTree instanceof ForExpr {
363+
override BlockExpr getLoopBody() { result = ForExpr.super.getLoopBody() }
364+
365+
override Label getLabel() { result = ForExpr.super.getLabel() }
366+
367+
override predicate entry(AstNode n) { first(super.getPat(), n) }
368+
369+
override predicate first(AstNode node) { first(super.getIterable(), node) }
370+
371+
override predicate succ(AstNode pred, AstNode succ, Completion c) {
372+
super.succ(pred, succ, c)
373+
or
374+
last(super.getIterable(), pred, c) and
375+
first(super.getPat(), succ) and
376+
completionIsNormal(c)
377+
or
378+
last(super.getPat(), pred, c) and
379+
c.(MatchCompletion).succeeded() and
380+
first(this.getLoopBody(), succ)
381+
or
382+
last(super.getPat(), pred, c) and
383+
c.(MatchCompletion).failed() and
384+
succ = this
385+
}
386+
387+
override predicate last(AstNode last, Completion c) {
388+
super.last(last, c)
389+
or
390+
last(super.getIterable(), last, c) and
391+
not completionIsNormal(c)
392+
}
393+
}
394+
356395
class MatchArmTree extends ControlFlowTree instanceof MatchArm {
357396
override predicate propagatesAbnormal(AstNode child) { child = super.getExpr() }
358397

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
deadEnd
22
| test.rs:230:28:230:33 | ... < ... |
33
| test.rs:245:30:245:48 | BlockExpr |
4-
scopeNoFirst
5-
| test.rs:65:5:72:5 | test_for |

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,27 @@
122122
| test.rs:61:13:61:21 | ... = ... | test.rs:56:17:62:9 | BlockExpr | |
123123
| test.rs:61:13:61:22 | ExprStmt | test.rs:61:13:61:13 | PathExpr | |
124124
| test.rs:61:17:61:21 | false | test.rs:61:13:61:21 | ... = ... | |
125+
| test.rs:65:5:72:5 | enter test_for | test.rs:66:18:66:18 | 0 | |
126+
| test.rs:65:5:72:5 | exit test_for (normal) | test.rs:65:5:72:5 | exit test_for | |
127+
| test.rs:65:25:72:5 | BlockExpr | test.rs:65:5:72:5 | exit test_for (normal) | |
128+
| test.rs:66:9:71:9 | ForExpr | test.rs:65:25:72:5 | BlockExpr | |
129+
| test.rs:66:13:66:13 | i | test.rs:66:9:71:9 | ForExpr | no-match |
130+
| test.rs:66:13:66:13 | i | test.rs:67:13:69:13 | ExprStmt | match |
131+
| test.rs:66:18:66:18 | 0 | test.rs:66:21:66:22 | 10 | |
132+
| test.rs:66:18:66:22 | RangeExpr | test.rs:66:13:66:13 | i | |
133+
| test.rs:66:21:66:22 | 10 | test.rs:66:18:66:22 | RangeExpr | |
134+
| test.rs:66:24:71:9 | BlockExpr | test.rs:66:13:66:13 | i | |
135+
| test.rs:67:13:69:13 | ExprStmt | test.rs:67:17:67:17 | i | |
136+
| test.rs:67:13:69:13 | IfExpr | test.rs:70:13:70:14 | ExprStmt | |
137+
| test.rs:67:16:67:23 | ParenExpr | test.rs:67:13:69:13 | IfExpr | false |
138+
| test.rs:67:16:67:23 | ParenExpr | test.rs:68:17:68:22 | ExprStmt | true |
139+
| test.rs:67:17:67:17 | i | test.rs:67:22:67:22 | j | |
140+
| test.rs:67:17:67:22 | ... == ... | test.rs:67:16:67:23 | ParenExpr | |
141+
| test.rs:67:22:67:22 | j | test.rs:67:17:67:22 | ... == ... | |
142+
| test.rs:68:17:68:21 | BreakExpr | test.rs:66:9:71:9 | ForExpr | break |
143+
| test.rs:68:17:68:22 | ExprStmt | test.rs:68:17:68:21 | BreakExpr | |
144+
| test.rs:70:13:70:13 | 1 | test.rs:66:24:71:9 | BlockExpr | |
145+
| test.rs:70:13:70:14 | ExprStmt | test.rs:70:13:70:13 | 1 | |
125146
| test.rs:75:1:78:1 | enter test_nested_function | test.rs:76:5:76:28 | LetStmt | |
126147
| test.rs:75:1:78:1 | exit test_nested_function (normal) | test.rs:75:1:78:1 | exit test_nested_function | |
127148
| test.rs:75:40:78:1 | BlockExpr | test.rs:75:1:78:1 | exit test_nested_function (normal) | |

0 commit comments

Comments
 (0)