Skip to content

Commit 6a87eb0

Browse files
authored
Merge pull request github#17696 from hvitved/rust/captured-variables
Rust: Account for captured variables
2 parents 8352d17 + aa7215b commit 6a87eb0

File tree

7 files changed

+364
-111
lines changed

7 files changed

+364
-111
lines changed

rust/ql/lib/codeql/rust/elements/internal/VariableImpl.qll

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
private import rust
22
private import codeql.rust.elements.internal.generated.ParentChild
33
private import codeql.rust.elements.internal.PathExprImpl::Impl as PathExprImpl
4+
private import codeql.util.DenseRank
45

56
module Impl {
67
/**
@@ -119,6 +120,9 @@ module Impl {
119120
result = let.getInitializer()
120121
)
121122
}
123+
124+
/** Holds if this variable is captured. */
125+
predicate isCaptured() { this.getAnAccess().isCapture() }
122126
}
123127

124128
/** A path expression that may access a local variable. */
@@ -251,7 +255,7 @@ module Impl {
251255
// Use the location of the inner scope as the location of the access, instead of the
252256
// actual access location. This allows us to collapse multiple accesses in inner
253257
// scopes to a single entity
254-
scope.getLocation().hasLocationInfo(_, startline, startcolumn, endline, endcolumn)
258+
inner.getLocation().hasLocationInfo(_, startline, startcolumn, endline, endcolumn)
255259
)
256260
}
257261

@@ -334,18 +338,30 @@ module Impl {
334338
}
335339
}
336340

341+
private module DenseRankInput implements DenseRankInputSig3 {
342+
class C1 = VariableScope;
343+
344+
class C2 = string;
345+
346+
class Ranked = VariableOrAccessCand;
347+
348+
int getRank(VariableScope scope, string name, VariableOrAccessCand v) {
349+
v =
350+
rank[result](VariableOrAccessCand v0, int startline, int startcolumn, int endline,
351+
int endcolumn |
352+
v0.rankBy(name, scope, startline, startcolumn, endline, endcolumn)
353+
|
354+
v0 order by startline, startcolumn, endline, endcolumn
355+
)
356+
}
357+
}
358+
337359
/**
338360
* Gets the rank of `v` amongst all other declarations or access candidates
339361
* to a variable named `name` in the variable scope `scope`.
340362
*/
341363
private int rankVariableOrAccess(VariableScope scope, string name, VariableOrAccessCand v) {
342-
v =
343-
rank[result + 1](VariableOrAccessCand v0, int startline, int startcolumn, int endline,
344-
int endcolumn |
345-
v0.rankBy(name, scope, startline, startcolumn, endline, endcolumn)
346-
|
347-
v0 order by startline, startcolumn, endline, endcolumn
348-
)
364+
result = DenseRank3<DenseRankInput>::denseRank(scope, name, v) - 1
349365
}
350366

351367
/**
@@ -379,16 +395,21 @@ module Impl {
379395
)
380396
}
381397

398+
private import codeql.rust.controlflow.internal.Scope
399+
382400
/** A variable access. */
383401
class VariableAccess extends PathExprImpl::PathExpr instanceof VariableAccessCand {
384402
private string name;
385403
private Variable v;
386404

387-
VariableAccess() { variableAccess(_, name, v, this) }
405+
VariableAccess() { variableAccess(name, v, this) }
388406

389407
/** Gets the variable being accessed. */
390408
Variable getVariable() { result = v }
391409

410+
/** Holds if this access is a capture. */
411+
predicate isCapture() { scopeOfAst(this) != scopeOfAst(v.getPat()) }
412+
392413
override string toString() { result = name }
393414

394415
override string getAPrimaryQlClass() { result = "VariableAccess" }
@@ -426,10 +447,10 @@ module Impl {
426447
MkVariable(AstNode definingNode, string name) { variableDecl(definingNode, _, name) }
427448

428449
cached
429-
predicate variableAccess(VariableScope scope, string name, Variable v, VariableAccessCand cand) {
450+
predicate variableAccess(string name, Variable v, VariableAccessCand cand) {
430451
v =
431452
min(Variable v0, int nestLevel |
432-
variableReachesCand(scope, name, v0, cand, nestLevel)
453+
variableReachesCand(_, name, v0, cand, nestLevel)
433454
|
434455
v0 order by nestLevel
435456
)

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

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,42 +20,42 @@ edges
2020
| test.rs:10:9:22:9 | ExprStmt | test.rs:11:13:11:24 | ExprStmt | |
2121
| test.rs:10:9:22:9 | LoopExpr | test.rs:23:9:23:20 | ExprStmt | |
2222
| test.rs:10:14:22:9 | BlockExpr | test.rs:11:13:11:24 | ExprStmt | |
23-
| test.rs:11:13:11:13 | PathExpr | test.rs:11:17:11:20 | PathExpr | |
23+
| test.rs:11:13:11:13 | i | test.rs:11:17:11:20 | PathExpr | |
2424
| test.rs:11:13:11:23 | ... = ... | test.rs:12:13:14:13 | ExprStmt | |
25-
| test.rs:11:13:11:24 | ExprStmt | test.rs:11:13:11:13 | PathExpr | |
26-
| test.rs:11:17:11:20 | PathExpr | test.rs:11:22:11:22 | PathExpr | |
25+
| test.rs:11:13:11:24 | ExprStmt | test.rs:11:13:11:13 | i | |
26+
| test.rs:11:17:11:20 | PathExpr | test.rs:11:22:11:22 | i | |
2727
| test.rs:11:17:11:23 | CallExpr | test.rs:11:13:11:23 | ... = ... | |
28-
| test.rs:11:22:11:22 | PathExpr | test.rs:11:17:11:23 | CallExpr | |
29-
| test.rs:12:13:14:13 | ExprStmt | test.rs:12:16:12:16 | PathExpr | |
28+
| test.rs:11:22:11:22 | i | test.rs:11:17:11:23 | CallExpr | |
29+
| test.rs:12:13:14:13 | ExprStmt | test.rs:12:16:12:16 | i | |
3030
| test.rs:12:13:14:13 | IfExpr | test.rs:15:13:17:13 | ExprStmt | |
31-
| test.rs:12:16:12:16 | PathExpr | test.rs:12:20:12:24 | 10000 | |
31+
| test.rs:12:16:12:16 | i | test.rs:12:20:12:24 | 10000 | |
3232
| test.rs:12:16:12:24 | ... > ... | test.rs:12:13:14:13 | IfExpr | false |
3333
| test.rs:12:16:12:24 | ... > ... | test.rs:13:17:13:29 | ExprStmt | true |
3434
| test.rs:12:20:12:24 | 10000 | test.rs:12:16:12:24 | ... > ... | |
3535
| test.rs:13:17:13:28 | ReturnExpr | test.rs:8:5:24:5 | exit test_break_and_continue (normal) | return |
3636
| test.rs:13:17:13:29 | ExprStmt | test.rs:13:24:13:28 | false | |
3737
| test.rs:13:24:13:28 | false | test.rs:13:17:13:28 | ReturnExpr | |
38-
| test.rs:15:13:17:13 | ExprStmt | test.rs:15:16:15:16 | PathExpr | |
38+
| test.rs:15:13:17:13 | ExprStmt | test.rs:15:16:15:16 | i | |
3939
| test.rs:15:13:17:13 | IfExpr | test.rs:18:13:20:13 | ExprStmt | |
40-
| test.rs:15:16:15:16 | PathExpr | test.rs:15:21:15:21 | 1 | |
40+
| test.rs:15:16:15:16 | i | test.rs:15:21:15:21 | 1 | |
4141
| test.rs:15:16:15:21 | ... == ... | test.rs:15:13:17:13 | IfExpr | false |
4242
| test.rs:15:16:15:21 | ... == ... | test.rs:16:17:16:22 | ExprStmt | true |
4343
| test.rs:15:21:15:21 | 1 | test.rs:15:16:15:21 | ... == ... | |
4444
| test.rs:16:17:16:21 | BreakExpr | test.rs:10:9:22:9 | LoopExpr | break |
4545
| test.rs:16:17:16:22 | ExprStmt | test.rs:16:17:16:21 | BreakExpr | |
46-
| test.rs:18:13:20:13 | ExprStmt | test.rs:18:16:18:16 | PathExpr | |
47-
| test.rs:18:13:20:13 | IfExpr | test.rs:21:13:21:13 | PathExpr | |
48-
| test.rs:18:16:18:16 | PathExpr | test.rs:18:20:18:20 | 2 | |
46+
| test.rs:18:13:20:13 | ExprStmt | test.rs:18:16:18:16 | i | |
47+
| test.rs:18:13:20:13 | IfExpr | test.rs:21:13:21:13 | i | |
48+
| test.rs:18:16:18:16 | i | test.rs:18:20:18:20 | 2 | |
4949
| test.rs:18:16:18:20 | ... % ... | test.rs:18:25:18:25 | 0 | |
5050
| test.rs:18:16:18:25 | ... != ... | test.rs:18:13:20:13 | IfExpr | false |
5151
| test.rs:18:16:18:25 | ... != ... | test.rs:19:17:19:25 | ExprStmt | true |
5252
| test.rs:18:20:18:20 | 2 | test.rs:18:16:18:20 | ... % ... | |
5353
| test.rs:18:25:18:25 | 0 | test.rs:18:16:18:25 | ... != ... | |
5454
| test.rs:19:17:19:24 | ContinueExpr | test.rs:11:13:11:24 | ExprStmt | continue |
5555
| test.rs:19:17:19:25 | ExprStmt | test.rs:19:17:19:24 | ContinueExpr | |
56-
| test.rs:21:13:21:13 | PathExpr | test.rs:21:17:21:17 | PathExpr | |
56+
| test.rs:21:13:21:13 | i | test.rs:21:17:21:17 | i | |
5757
| test.rs:21:13:21:21 | ... = ... | test.rs:10:14:22:9 | BlockExpr | |
58-
| test.rs:21:17:21:17 | PathExpr | test.rs:21:21:21:21 | 2 | |
58+
| test.rs:21:17:21:17 | i | test.rs:21:21:21:21 | 2 | |
5959
| test.rs:21:17:21:21 | ... / ... | test.rs:21:13:21:21 | ... = ... | |
6060
| test.rs:21:21:21:21 | 2 | test.rs:21:17:21:21 | ... / ... | |
6161
| test.rs:23:9:23:19 | ReturnExpr | test.rs:8:5:24:5 | exit test_break_and_continue (normal) | return |
@@ -134,9 +134,9 @@ edges
134134
| test.rs:72:21:72:21 | 0 | test.rs:72:17:72:21 | ... > ... | |
135135
| test.rs:73:17:73:21 | BreakExpr | test.rs:70:9:76:9 | WhileExpr | break |
136136
| test.rs:73:17:73:22 | ExprStmt | test.rs:73:17:73:21 | BreakExpr | |
137-
| test.rs:75:13:75:13 | PathExpr | test.rs:75:17:75:21 | false | |
137+
| test.rs:75:13:75:13 | b | test.rs:75:17:75:21 | false | |
138138
| test.rs:75:13:75:21 | ... = ... | test.rs:70:17:76:9 | BlockExpr | |
139-
| test.rs:75:13:75:22 | ExprStmt | test.rs:75:13:75:13 | PathExpr | |
139+
| test.rs:75:13:75:22 | ExprStmt | test.rs:75:13:75:13 | b | |
140140
| test.rs:75:17:75:21 | false | test.rs:75:13:75:21 | ... = ... | |
141141
| test.rs:79:5:86:5 | enter test_while_let | test.rs:80:9:80:29 | LetStmt | |
142142
| test.rs:79:5:86:5 | exit test_while_let (normal) | test.rs:79:5:86:5 | exit test_while_let | |
@@ -230,13 +230,13 @@ edges
230230
| test.rs:122:28:124:9 | BlockExpr | test.rs:122:9:124:9 | IfExpr | |
231231
| test.rs:123:13:123:13 | n | test.rs:122:28:124:9 | BlockExpr | |
232232
| test.rs:125:9:125:9 | 0 | test.rs:121:43:126:5 | BlockExpr | |
233-
| test.rs:128:5:134:5 | enter test_nested_if | test.rs:129:16:129:16 | PathExpr | |
233+
| test.rs:128:5:134:5 | enter test_nested_if | test.rs:129:16:129:16 | a | |
234234
| test.rs:128:5:134:5 | exit test_nested_if (normal) | test.rs:128:5:134:5 | exit test_nested_if | |
235235
| test.rs:128:38:134:5 | BlockExpr | test.rs:128:5:134:5 | exit test_nested_if (normal) | |
236236
| test.rs:129:9:133:9 | IfExpr | test.rs:128:38:134:5 | BlockExpr | |
237237
| test.rs:129:13:129:48 | [boolean(false)] IfExpr | test.rs:132:13:132:13 | 0 | false |
238238
| test.rs:129:13:129:48 | [boolean(true)] IfExpr | test.rs:130:13:130:13 | 1 | true |
239-
| test.rs:129:16:129:16 | PathExpr | test.rs:129:20:129:20 | 0 | |
239+
| test.rs:129:16:129:16 | a | test.rs:129:20:129:20 | 0 | |
240240
| test.rs:129:16:129:20 | ... < ... | test.rs:129:24:129:24 | a | true |
241241
| test.rs:129:16:129:20 | ... < ... | test.rs:129:41:129:41 | a | false |
242242
| test.rs:129:20:129:20 | 0 | test.rs:129:16:129:20 | ... < ... | |

0 commit comments

Comments
 (0)