Skip to content

Commit 67a06cb

Browse files
committed
Rust: Support loop in CFG
1 parent 076dd07 commit 67a06cb

3 files changed

Lines changed: 129 additions & 45 deletions

File tree

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,39 @@ class IfExprTree extends PostOrderTree instanceof IfExpr {
117117
}
118118
}
119119

120+
class ExprStmtTree extends StandardPostOrderTree instanceof ExprStmt {
121+
override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() }
122+
}
123+
120124
class LetExprTree extends StandardPostOrderTree instanceof LetExpr {
121125
override ControlFlowTree getChildNode(int i) { i = 0 and result = super.getExpr() }
122126
}
123127

128+
class LetStmtTree extends StandardPostOrderTree instanceof LetStmt {
129+
override ControlFlowTree getChildNode(int i) {
130+
// TODO: For now we ignore the else branch (`super.getElse`). This branch
131+
// is guaranteed to be diverging so will need special treatment in the CFG.
132+
i = 0 and result = super.getInitializer()
133+
}
134+
}
135+
136+
class LoopExprTree extends PostOrderTree instanceof LoopExpr {
137+
override predicate propagatesAbnormal(AstNode child) { child = super.getBody() }
138+
139+
override predicate first(AstNode node) { first(super.getBody(), node) }
140+
141+
override predicate succ(AstNode pred, AstNode succ, Completion c) {
142+
// Edge from the last node in the body to the loop itself
143+
last(super.getBody(), pred, c) and
144+
completionIsNormal(c) and
145+
succ = this
146+
or
147+
// Tie the knot with an edge from the loop back to the first node
148+
pred = this and
149+
first(super.getBody(), succ)
150+
}
151+
}
152+
124153
class LiteralExprTree extends LeafTree instanceof LiteralExpr { }
125154

126155
class PathExprTree extends LeafTree instanceof PathExpr { }

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

Lines changed: 93 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,36 @@ nodes
1414
| test.rs:4:12:6:5 | BlockExpr | semmle.order | 13 |
1515
| test.rs:5:9:5:20 | CallExpr | semmle.order | 14 |
1616
| test.rs:5:19:5:19 | LiteralExpr | semmle.order | 15 |
17-
| test.rs:9:1:16:1 | decrement | semmle.order | 16 |
18-
| test.rs:9:1:16:1 | enter decrement | semmle.order | 17 |
19-
| test.rs:9:1:16:1 | exit decrement | semmle.order | 18 |
20-
| test.rs:9:1:16:1 | exit decrement (normal) | semmle.order | 19 |
21-
| test.rs:9:29:16:1 | BlockExpr | semmle.order | 20 |
22-
| test.rs:11:5:15:5 | IfExpr | semmle.order | 21 |
23-
| test.rs:11:8:11:8 | PathExpr | semmle.order | 22 |
24-
| test.rs:11:8:11:13 | BinaryOpExpr | semmle.order | 23 |
25-
| test.rs:11:13:11:13 | LiteralExpr | semmle.order | 24 |
26-
| test.rs:11:15:13:5 | BlockExpr | semmle.order | 25 |
27-
| test.rs:12:9:12:9 | LiteralExpr | semmle.order | 26 |
28-
| test.rs:13:12:15:5 | BlockExpr | semmle.order | 27 |
29-
| test.rs:14:9:14:9 | PathExpr | semmle.order | 28 |
30-
| test.rs:14:9:14:13 | BinaryOpExpr | semmle.order | 29 |
31-
| test.rs:14:13:14:13 | LiteralExpr | semmle.order | 30 |
17+
| test.rs:9:1:14:1 | enter spin | semmle.order | 16 |
18+
| test.rs:9:1:14:1 | exit spin | semmle.order | 17 |
19+
| test.rs:9:1:14:1 | exit spin (normal) | semmle.order | 18 |
20+
| test.rs:9:1:14:1 | spin | semmle.order | 19 |
21+
| test.rs:9:17:14:1 | BlockExpr | semmle.order | 20 |
22+
| test.rs:10:9:10:13 | LetStmt | semmle.order | 21 |
23+
| test.rs:10:17:10:17 | LiteralExpr | semmle.order | 22 |
24+
| test.rs:11:5:13:5 | LoopExpr | semmle.order | 23 |
25+
| test.rs:11:10:13:5 | BlockExpr | semmle.order | 24 |
26+
| test.rs:12:9:12:9 | PathExpr | semmle.order | 25 |
27+
| test.rs:12:9:12:14 | BinaryOpExpr | semmle.order | 26 |
28+
| test.rs:12:9:12:14 | ExprStmt | semmle.order | 27 |
29+
| test.rs:12:14:12:14 | LiteralExpr | semmle.order | 28 |
30+
| test.rs:16:1:23:1 | decrement | semmle.order | 29 |
31+
| test.rs:16:1:23:1 | enter decrement | semmle.order | 30 |
32+
| test.rs:16:1:23:1 | exit decrement | semmle.order | 31 |
33+
| test.rs:16:1:23:1 | exit decrement (normal) | semmle.order | 32 |
34+
| test.rs:16:29:23:1 | BlockExpr | semmle.order | 33 |
35+
| test.rs:17:5:17:6 | ExprStmt | semmle.order | 34 |
36+
| test.rs:17:5:17:6 | LiteralExpr | semmle.order | 35 |
37+
| test.rs:18:5:22:5 | IfExpr | semmle.order | 36 |
38+
| test.rs:18:8:18:8 | PathExpr | semmle.order | 37 |
39+
| test.rs:18:8:18:13 | BinaryOpExpr | semmle.order | 38 |
40+
| test.rs:18:13:18:13 | LiteralExpr | semmle.order | 39 |
41+
| test.rs:18:15:20:5 | BlockExpr | semmle.order | 40 |
42+
| test.rs:19:9:19:9 | LiteralExpr | semmle.order | 41 |
43+
| test.rs:20:12:22:5 | BlockExpr | semmle.order | 42 |
44+
| test.rs:21:9:21:9 | PathExpr | semmle.order | 43 |
45+
| test.rs:21:9:21:13 | BinaryOpExpr | semmle.order | 44 |
46+
| test.rs:21:13:21:13 | LiteralExpr | semmle.order | 45 |
3247
edges
3348
| test.rs:1:1:7:1 | enter main | test.rs:2:8:2:12 | LiteralExpr | semmle.label | |
3449
| test.rs:1:1:7:1 | enter main | test.rs:2:8:2:12 | LiteralExpr | semmle.order | 1 |
@@ -60,33 +75,66 @@ edges
6075
| test.rs:5:9:5:20 | CallExpr | test.rs:4:12:6:5 | BlockExpr | semmle.order | 1 |
6176
| test.rs:5:19:5:19 | LiteralExpr | test.rs:5:9:5:20 | CallExpr | semmle.label | |
6277
| test.rs:5:19:5:19 | LiteralExpr | test.rs:5:9:5:20 | CallExpr | semmle.order | 1 |
63-
| test.rs:9:1:16:1 | decrement | test.rs:9:1:16:1 | exit decrement (normal) | semmle.label | |
64-
| test.rs:9:1:16:1 | decrement | test.rs:9:1:16:1 | exit decrement (normal) | semmle.order | 1 |
65-
| test.rs:9:1:16:1 | enter decrement | test.rs:11:8:11:8 | PathExpr | semmle.label | |
66-
| test.rs:9:1:16:1 | enter decrement | test.rs:11:8:11:8 | PathExpr | semmle.order | 1 |
67-
| test.rs:9:1:16:1 | exit decrement (normal) | test.rs:9:1:16:1 | exit decrement | semmle.label | |
68-
| test.rs:9:1:16:1 | exit decrement (normal) | test.rs:9:1:16:1 | exit decrement | semmle.order | 1 |
69-
| test.rs:9:29:16:1 | BlockExpr | test.rs:9:1:16:1 | decrement | semmle.label | |
70-
| test.rs:9:29:16:1 | BlockExpr | test.rs:9:1:16:1 | decrement | semmle.order | 1 |
71-
| test.rs:11:5:15:5 | IfExpr | test.rs:9:29:16:1 | BlockExpr | semmle.label | |
72-
| test.rs:11:5:15:5 | IfExpr | test.rs:9:29:16:1 | BlockExpr | semmle.order | 1 |
73-
| test.rs:11:8:11:8 | PathExpr | test.rs:11:13:11:13 | LiteralExpr | semmle.label | |
74-
| test.rs:11:8:11:8 | PathExpr | test.rs:11:13:11:13 | LiteralExpr | semmle.order | 1 |
75-
| test.rs:11:8:11:13 | BinaryOpExpr | test.rs:12:9:12:9 | LiteralExpr | semmle.label | true |
76-
| test.rs:11:8:11:13 | BinaryOpExpr | test.rs:12:9:12:9 | LiteralExpr | semmle.order | 1 |
77-
| test.rs:11:8:11:13 | BinaryOpExpr | test.rs:14:9:14:9 | PathExpr | semmle.label | false |
78-
| test.rs:11:8:11:13 | BinaryOpExpr | test.rs:14:9:14:9 | PathExpr | semmle.order | 2 |
79-
| test.rs:11:13:11:13 | LiteralExpr | test.rs:11:8:11:13 | BinaryOpExpr | semmle.label | |
80-
| test.rs:11:13:11:13 | LiteralExpr | test.rs:11:8:11:13 | BinaryOpExpr | semmle.order | 1 |
81-
| test.rs:11:15:13:5 | BlockExpr | test.rs:11:5:15:5 | IfExpr | semmle.label | |
82-
| test.rs:11:15:13:5 | BlockExpr | test.rs:11:5:15:5 | IfExpr | semmle.order | 1 |
83-
| test.rs:12:9:12:9 | LiteralExpr | test.rs:11:15:13:5 | BlockExpr | semmle.label | |
84-
| test.rs:12:9:12:9 | LiteralExpr | test.rs:11:15:13:5 | BlockExpr | semmle.order | 1 |
85-
| test.rs:13:12:15:5 | BlockExpr | test.rs:11:5:15:5 | IfExpr | semmle.label | |
86-
| test.rs:13:12:15:5 | BlockExpr | test.rs:11:5:15:5 | IfExpr | semmle.order | 1 |
87-
| test.rs:14:9:14:9 | PathExpr | test.rs:14:13:14:13 | LiteralExpr | semmle.label | |
88-
| test.rs:14:9:14:9 | PathExpr | test.rs:14:13:14:13 | LiteralExpr | semmle.order | 1 |
89-
| test.rs:14:9:14:13 | BinaryOpExpr | test.rs:13:12:15:5 | BlockExpr | semmle.label | |
90-
| test.rs:14:9:14:13 | BinaryOpExpr | test.rs:13:12:15:5 | BlockExpr | semmle.order | 1 |
91-
| test.rs:14:13:14:13 | LiteralExpr | test.rs:14:9:14:13 | BinaryOpExpr | semmle.label | |
92-
| test.rs:14:13:14:13 | LiteralExpr | test.rs:14:9:14:13 | BinaryOpExpr | semmle.order | 1 |
78+
| test.rs:9:1:14:1 | enter spin | test.rs:10:17:10:17 | LiteralExpr | semmle.label | |
79+
| test.rs:9:1:14:1 | enter spin | test.rs:10:17:10:17 | LiteralExpr | semmle.order | 1 |
80+
| test.rs:9:1:14:1 | exit spin (normal) | test.rs:9:1:14:1 | exit spin | semmle.label | |
81+
| test.rs:9:1:14:1 | exit spin (normal) | test.rs:9:1:14:1 | exit spin | semmle.order | 1 |
82+
| test.rs:9:1:14:1 | spin | test.rs:9:1:14:1 | exit spin (normal) | semmle.label | |
83+
| test.rs:9:1:14:1 | spin | test.rs:9:1:14:1 | exit spin (normal) | semmle.order | 1 |
84+
| test.rs:9:17:14:1 | BlockExpr | test.rs:9:1:14:1 | spin | semmle.label | |
85+
| test.rs:9:17:14:1 | BlockExpr | test.rs:9:1:14:1 | spin | semmle.order | 1 |
86+
| test.rs:10:9:10:13 | LetStmt | test.rs:12:9:12:9 | PathExpr | semmle.label | |
87+
| test.rs:10:9:10:13 | LetStmt | test.rs:12:9:12:9 | PathExpr | semmle.order | 1 |
88+
| test.rs:10:17:10:17 | LiteralExpr | test.rs:10:9:10:13 | LetStmt | semmle.label | |
89+
| test.rs:10:17:10:17 | LiteralExpr | test.rs:10:9:10:13 | LetStmt | semmle.order | 1 |
90+
| test.rs:11:5:13:5 | LoopExpr | test.rs:9:17:14:1 | BlockExpr | semmle.label | |
91+
| test.rs:11:5:13:5 | LoopExpr | test.rs:9:17:14:1 | BlockExpr | semmle.order | 1 |
92+
| test.rs:11:5:13:5 | LoopExpr | test.rs:12:9:12:9 | PathExpr | semmle.label | , false, return, true |
93+
| test.rs:11:5:13:5 | LoopExpr | test.rs:12:9:12:9 | PathExpr | semmle.order | 2 |
94+
| test.rs:11:5:13:5 | LoopExpr | test.rs:12:9:12:9 | PathExpr | semmle.order | 3 |
95+
| test.rs:11:5:13:5 | LoopExpr | test.rs:12:9:12:9 | PathExpr | semmle.order | 4 |
96+
| test.rs:11:5:13:5 | LoopExpr | test.rs:12:9:12:9 | PathExpr | semmle.order | 5 |
97+
| test.rs:11:10:13:5 | BlockExpr | test.rs:11:5:13:5 | LoopExpr | semmle.label | |
98+
| test.rs:11:10:13:5 | BlockExpr | test.rs:11:5:13:5 | LoopExpr | semmle.order | 1 |
99+
| test.rs:12:9:12:9 | PathExpr | test.rs:12:14:12:14 | LiteralExpr | semmle.label | |
100+
| test.rs:12:9:12:9 | PathExpr | test.rs:12:14:12:14 | LiteralExpr | semmle.order | 1 |
101+
| test.rs:12:9:12:14 | BinaryOpExpr | test.rs:12:9:12:14 | ExprStmt | semmle.label | |
102+
| test.rs:12:9:12:14 | BinaryOpExpr | test.rs:12:9:12:14 | ExprStmt | semmle.order | 1 |
103+
| test.rs:12:9:12:14 | ExprStmt | test.rs:11:10:13:5 | BlockExpr | semmle.label | |
104+
| test.rs:12:9:12:14 | ExprStmt | test.rs:11:10:13:5 | BlockExpr | semmle.order | 1 |
105+
| test.rs:12:14:12:14 | LiteralExpr | test.rs:12:9:12:14 | BinaryOpExpr | semmle.label | |
106+
| test.rs:12:14:12:14 | LiteralExpr | test.rs:12:9:12:14 | BinaryOpExpr | semmle.order | 1 |
107+
| test.rs:16:1:23:1 | decrement | test.rs:16:1:23:1 | exit decrement (normal) | semmle.label | |
108+
| test.rs:16:1:23:1 | decrement | test.rs:16:1:23:1 | exit decrement (normal) | semmle.order | 1 |
109+
| test.rs:16:1:23:1 | enter decrement | test.rs:17:5:17:6 | LiteralExpr | semmle.label | |
110+
| test.rs:16:1:23:1 | enter decrement | test.rs:17:5:17:6 | LiteralExpr | semmle.order | 1 |
111+
| test.rs:16:1:23:1 | exit decrement (normal) | test.rs:16:1:23:1 | exit decrement | semmle.label | |
112+
| test.rs:16:1:23:1 | exit decrement (normal) | test.rs:16:1:23:1 | exit decrement | semmle.order | 1 |
113+
| test.rs:16:29:23:1 | BlockExpr | test.rs:16:1:23:1 | decrement | semmle.label | |
114+
| test.rs:16:29:23:1 | BlockExpr | test.rs:16:1:23:1 | decrement | semmle.order | 1 |
115+
| test.rs:17:5:17:6 | ExprStmt | test.rs:18:8:18:8 | PathExpr | semmle.label | |
116+
| test.rs:17:5:17:6 | ExprStmt | test.rs:18:8:18:8 | PathExpr | semmle.order | 1 |
117+
| test.rs:17:5:17:6 | LiteralExpr | test.rs:17:5:17:6 | ExprStmt | semmle.label | |
118+
| test.rs:17:5:17:6 | LiteralExpr | test.rs:17:5:17:6 | ExprStmt | semmle.order | 1 |
119+
| test.rs:18:5:22:5 | IfExpr | test.rs:16:29:23:1 | BlockExpr | semmle.label | |
120+
| test.rs:18:5:22:5 | IfExpr | test.rs:16:29:23:1 | BlockExpr | semmle.order | 1 |
121+
| test.rs:18:8:18:8 | PathExpr | test.rs:18:13:18:13 | LiteralExpr | semmle.label | |
122+
| test.rs:18:8:18:8 | PathExpr | test.rs:18:13:18:13 | LiteralExpr | semmle.order | 1 |
123+
| test.rs:18:8:18:13 | BinaryOpExpr | test.rs:19:9:19:9 | LiteralExpr | semmle.label | true |
124+
| test.rs:18:8:18:13 | BinaryOpExpr | test.rs:19:9:19:9 | LiteralExpr | semmle.order | 1 |
125+
| test.rs:18:8:18:13 | BinaryOpExpr | test.rs:21:9:21:9 | PathExpr | semmle.label | false |
126+
| test.rs:18:8:18:13 | BinaryOpExpr | test.rs:21:9:21:9 | PathExpr | semmle.order | 2 |
127+
| test.rs:18:13:18:13 | LiteralExpr | test.rs:18:8:18:13 | BinaryOpExpr | semmle.label | |
128+
| test.rs:18:13:18:13 | LiteralExpr | test.rs:18:8:18:13 | BinaryOpExpr | semmle.order | 1 |
129+
| test.rs:18:15:20:5 | BlockExpr | test.rs:18:5:22:5 | IfExpr | semmle.label | |
130+
| test.rs:18:15:20:5 | BlockExpr | test.rs:18:5:22:5 | IfExpr | semmle.order | 1 |
131+
| test.rs:19:9:19:9 | LiteralExpr | test.rs:18:15:20:5 | BlockExpr | semmle.label | |
132+
| test.rs:19:9:19:9 | LiteralExpr | test.rs:18:15:20:5 | BlockExpr | semmle.order | 1 |
133+
| test.rs:20:12:22:5 | BlockExpr | test.rs:18:5:22:5 | IfExpr | semmle.label | |
134+
| test.rs:20:12:22:5 | BlockExpr | test.rs:18:5:22:5 | IfExpr | semmle.order | 1 |
135+
| test.rs:21:9:21:9 | PathExpr | test.rs:21:13:21:13 | LiteralExpr | semmle.label | |
136+
| test.rs:21:9:21:9 | PathExpr | test.rs:21:13:21:13 | LiteralExpr | semmle.order | 1 |
137+
| test.rs:21:9:21:13 | BinaryOpExpr | test.rs:20:12:22:5 | BlockExpr | semmle.label | |
138+
| test.rs:21:9:21:13 | BinaryOpExpr | test.rs:20:12:22:5 | BlockExpr | semmle.order | 1 |
139+
| test.rs:21:13:21:13 | LiteralExpr | test.rs:21:9:21:13 | BinaryOpExpr | semmle.label | |
140+
| test.rs:21:13:21:13 | LiteralExpr | test.rs:21:9:21:13 | BinaryOpExpr | semmle.order | 1 |

rust/ql/test/library-tests/controlflow/test.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ fn main() -> i64 {
66
}
77
}
88

9+
fn spin(n: i64) {
10+
let mut i = 0;
11+
loop {
12+
i += 1;
13+
}
14+
}
15+
916
fn decrement(n: i64) -> i64 {
1017
12;
1118
if n == 0 {

0 commit comments

Comments
 (0)