diff --git a/rust/ql/lib/codeql/rust/elements/internal/VariableImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/VariableImpl.qll index b9e9bb7cb48a..99cdeba4e1b2 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/VariableImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/VariableImpl.qll @@ -1,6 +1,7 @@ private import rust private import codeql.rust.elements.internal.generated.ParentChild private import codeql.rust.elements.internal.PathExprImpl::Impl as PathExprImpl +private import codeql.util.DenseRank module Impl { /** @@ -119,6 +120,9 @@ module Impl { result = let.getInitializer() ) } + + /** Holds if this variable is captured. */ + predicate isCaptured() { this.getAnAccess().isCapture() } } /** A path expression that may access a local variable. */ @@ -251,7 +255,7 @@ module Impl { // Use the location of the inner scope as the location of the access, instead of the // actual access location. This allows us to collapse multiple accesses in inner // scopes to a single entity - scope.getLocation().hasLocationInfo(_, startline, startcolumn, endline, endcolumn) + inner.getLocation().hasLocationInfo(_, startline, startcolumn, endline, endcolumn) ) } @@ -334,18 +338,30 @@ module Impl { } } + private module DenseRankInput implements DenseRankInputSig3 { + class C1 = VariableScope; + + class C2 = string; + + class Ranked = VariableOrAccessCand; + + int getRank(VariableScope scope, string name, VariableOrAccessCand v) { + v = + rank[result](VariableOrAccessCand v0, int startline, int startcolumn, int endline, + int endcolumn | + v0.rankBy(name, scope, startline, startcolumn, endline, endcolumn) + | + v0 order by startline, startcolumn, endline, endcolumn + ) + } + } + /** * Gets the rank of `v` amongst all other declarations or access candidates * to a variable named `name` in the variable scope `scope`. */ private int rankVariableOrAccess(VariableScope scope, string name, VariableOrAccessCand v) { - v = - rank[result + 1](VariableOrAccessCand v0, int startline, int startcolumn, int endline, - int endcolumn | - v0.rankBy(name, scope, startline, startcolumn, endline, endcolumn) - | - v0 order by startline, startcolumn, endline, endcolumn - ) + result = DenseRank3::denseRank(scope, name, v) - 1 } /** @@ -379,16 +395,21 @@ module Impl { ) } + private import codeql.rust.controlflow.internal.Scope + /** A variable access. */ class VariableAccess extends PathExprImpl::PathExpr instanceof VariableAccessCand { private string name; private Variable v; - VariableAccess() { variableAccess(_, name, v, this) } + VariableAccess() { variableAccess(name, v, this) } /** Gets the variable being accessed. */ Variable getVariable() { result = v } + /** Holds if this access is a capture. */ + predicate isCapture() { scopeOfAst(this) != scopeOfAst(v.getPat()) } + override string toString() { result = name } override string getAPrimaryQlClass() { result = "VariableAccess" } @@ -426,10 +447,10 @@ module Impl { MkVariable(AstNode definingNode, string name) { variableDecl(definingNode, _, name) } cached - predicate variableAccess(VariableScope scope, string name, Variable v, VariableAccessCand cand) { + predicate variableAccess(string name, Variable v, VariableAccessCand cand) { v = min(Variable v0, int nestLevel | - variableReachesCand(scope, name, v0, cand, nestLevel) + variableReachesCand(_, name, v0, cand, nestLevel) | v0 order by nestLevel ) diff --git a/rust/ql/test/library-tests/controlflow/Cfg.expected b/rust/ql/test/library-tests/controlflow/Cfg.expected index 61b71f15118d..036dca8af5a3 100644 --- a/rust/ql/test/library-tests/controlflow/Cfg.expected +++ b/rust/ql/test/library-tests/controlflow/Cfg.expected @@ -20,32 +20,32 @@ edges | test.rs:10:9:22:9 | ExprStmt | test.rs:11:13:11:24 | ExprStmt | | | test.rs:10:9:22:9 | LoopExpr | test.rs:23:9:23:20 | ExprStmt | | | test.rs:10:14:22:9 | BlockExpr | test.rs:11:13:11:24 | ExprStmt | | -| test.rs:11:13:11:13 | PathExpr | test.rs:11:17:11:20 | PathExpr | | +| test.rs:11:13:11:13 | i | test.rs:11:17:11:20 | PathExpr | | | test.rs:11:13:11:23 | ... = ... | test.rs:12:13:14:13 | ExprStmt | | -| test.rs:11:13:11:24 | ExprStmt | test.rs:11:13:11:13 | PathExpr | | -| test.rs:11:17:11:20 | PathExpr | test.rs:11:22:11:22 | PathExpr | | +| test.rs:11:13:11:24 | ExprStmt | test.rs:11:13:11:13 | i | | +| test.rs:11:17:11:20 | PathExpr | test.rs:11:22:11:22 | i | | | test.rs:11:17:11:23 | CallExpr | test.rs:11:13:11:23 | ... = ... | | -| test.rs:11:22:11:22 | PathExpr | test.rs:11:17:11:23 | CallExpr | | -| test.rs:12:13:14:13 | ExprStmt | test.rs:12:16:12:16 | PathExpr | | +| test.rs:11:22:11:22 | i | test.rs:11:17:11:23 | CallExpr | | +| test.rs:12:13:14:13 | ExprStmt | test.rs:12:16:12:16 | i | | | test.rs:12:13:14:13 | IfExpr | test.rs:15:13:17:13 | ExprStmt | | -| test.rs:12:16:12:16 | PathExpr | test.rs:12:20:12:24 | 10000 | | +| test.rs:12:16:12:16 | i | test.rs:12:20:12:24 | 10000 | | | test.rs:12:16:12:24 | ... > ... | test.rs:12:13:14:13 | IfExpr | false | | test.rs:12:16:12:24 | ... > ... | test.rs:13:17:13:29 | ExprStmt | true | | test.rs:12:20:12:24 | 10000 | test.rs:12:16:12:24 | ... > ... | | | test.rs:13:17:13:28 | ReturnExpr | test.rs:8:5:24:5 | exit test_break_and_continue (normal) | return | | test.rs:13:17:13:29 | ExprStmt | test.rs:13:24:13:28 | false | | | test.rs:13:24:13:28 | false | test.rs:13:17:13:28 | ReturnExpr | | -| test.rs:15:13:17:13 | ExprStmt | test.rs:15:16:15:16 | PathExpr | | +| test.rs:15:13:17:13 | ExprStmt | test.rs:15:16:15:16 | i | | | test.rs:15:13:17:13 | IfExpr | test.rs:18:13:20:13 | ExprStmt | | -| test.rs:15:16:15:16 | PathExpr | test.rs:15:21:15:21 | 1 | | +| test.rs:15:16:15:16 | i | test.rs:15:21:15:21 | 1 | | | test.rs:15:16:15:21 | ... == ... | test.rs:15:13:17:13 | IfExpr | false | | test.rs:15:16:15:21 | ... == ... | test.rs:16:17:16:22 | ExprStmt | true | | test.rs:15:21:15:21 | 1 | test.rs:15:16:15:21 | ... == ... | | | test.rs:16:17:16:21 | BreakExpr | test.rs:10:9:22:9 | LoopExpr | break | | test.rs:16:17:16:22 | ExprStmt | test.rs:16:17:16:21 | BreakExpr | | -| test.rs:18:13:20:13 | ExprStmt | test.rs:18:16:18:16 | PathExpr | | -| test.rs:18:13:20:13 | IfExpr | test.rs:21:13:21:13 | PathExpr | | -| test.rs:18:16:18:16 | PathExpr | test.rs:18:20:18:20 | 2 | | +| test.rs:18:13:20:13 | ExprStmt | test.rs:18:16:18:16 | i | | +| test.rs:18:13:20:13 | IfExpr | test.rs:21:13:21:13 | i | | +| test.rs:18:16:18:16 | i | test.rs:18:20:18:20 | 2 | | | test.rs:18:16:18:20 | ... % ... | test.rs:18:25:18:25 | 0 | | | test.rs:18:16:18:25 | ... != ... | test.rs:18:13:20:13 | IfExpr | false | | test.rs:18:16:18:25 | ... != ... | test.rs:19:17:19:25 | ExprStmt | true | @@ -53,9 +53,9 @@ edges | test.rs:18:25:18:25 | 0 | test.rs:18:16:18:25 | ... != ... | | | test.rs:19:17:19:24 | ContinueExpr | test.rs:11:13:11:24 | ExprStmt | continue | | test.rs:19:17:19:25 | ExprStmt | test.rs:19:17:19:24 | ContinueExpr | | -| test.rs:21:13:21:13 | PathExpr | test.rs:21:17:21:17 | PathExpr | | +| test.rs:21:13:21:13 | i | test.rs:21:17:21:17 | i | | | test.rs:21:13:21:21 | ... = ... | test.rs:10:14:22:9 | BlockExpr | | -| test.rs:21:17:21:17 | PathExpr | test.rs:21:21:21:21 | 2 | | +| test.rs:21:17:21:17 | i | test.rs:21:21:21:21 | 2 | | | test.rs:21:17:21:21 | ... / ... | test.rs:21:13:21:21 | ... = ... | | | test.rs:21:21:21:21 | 2 | test.rs:21:17:21:21 | ... / ... | | | 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 | test.rs:72:21:72:21 | 0 | test.rs:72:17:72:21 | ... > ... | | | test.rs:73:17:73:21 | BreakExpr | test.rs:70:9:76:9 | WhileExpr | break | | test.rs:73:17:73:22 | ExprStmt | test.rs:73:17:73:21 | BreakExpr | | -| test.rs:75:13:75:13 | PathExpr | test.rs:75:17:75:21 | false | | +| test.rs:75:13:75:13 | b | test.rs:75:17:75:21 | false | | | test.rs:75:13:75:21 | ... = ... | test.rs:70:17:76:9 | BlockExpr | | -| test.rs:75:13:75:22 | ExprStmt | test.rs:75:13:75:13 | PathExpr | | +| test.rs:75:13:75:22 | ExprStmt | test.rs:75:13:75:13 | b | | | test.rs:75:17:75:21 | false | test.rs:75:13:75:21 | ... = ... | | | test.rs:79:5:86:5 | enter test_while_let | test.rs:80:9:80:29 | LetStmt | | | 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 | test.rs:122:28:124:9 | BlockExpr | test.rs:122:9:124:9 | IfExpr | | | test.rs:123:13:123:13 | n | test.rs:122:28:124:9 | BlockExpr | | | test.rs:125:9:125:9 | 0 | test.rs:121:43:126:5 | BlockExpr | | -| test.rs:128:5:134:5 | enter test_nested_if | test.rs:129:16:129:16 | PathExpr | | +| test.rs:128:5:134:5 | enter test_nested_if | test.rs:129:16:129:16 | a | | | test.rs:128:5:134:5 | exit test_nested_if (normal) | test.rs:128:5:134:5 | exit test_nested_if | | | test.rs:128:38:134:5 | BlockExpr | test.rs:128:5:134:5 | exit test_nested_if (normal) | | | test.rs:129:9:133:9 | IfExpr | test.rs:128:38:134:5 | BlockExpr | | | test.rs:129:13:129:48 | [boolean(false)] IfExpr | test.rs:132:13:132:13 | 0 | false | | test.rs:129:13:129:48 | [boolean(true)] IfExpr | test.rs:130:13:130:13 | 1 | true | -| test.rs:129:16:129:16 | PathExpr | test.rs:129:20:129:20 | 0 | | +| test.rs:129:16:129:16 | a | test.rs:129:20:129:20 | 0 | | | test.rs:129:16:129:20 | ... < ... | test.rs:129:24:129:24 | a | true | | test.rs:129:16:129:20 | ... < ... | test.rs:129:41:129:41 | a | false | | test.rs:129:20:129:20 | 0 | test.rs:129:16:129:20 | ... < ... | | diff --git a/rust/ql/test/library-tests/variables/Cfg.expected b/rust/ql/test/library-tests/variables/Cfg.expected index 55b09cf6ace7..89e7aaec297e 100644 --- a/rust/ql/test/library-tests/variables/Cfg.expected +++ b/rust/ql/test/library-tests/variables/Cfg.expected @@ -602,90 +602,142 @@ edges | variables.rs:354:5:354:16 | CallExpr | variables.rs:351:17:355:1 | BlockExpr | | | variables.rs:354:5:354:17 | ExprStmt | variables.rs:354:5:354:13 | PathExpr | | | variables.rs:354:15:354:15 | x | variables.rs:354:5:354:16 | CallExpr | | -| variables.rs:357:1:383:1 | enter main | variables.rs:358:5:358:25 | ExprStmt | | -| variables.rs:357:1:383:1 | exit main (normal) | variables.rs:357:1:383:1 | exit main | | -| variables.rs:357:11:383:1 | BlockExpr | variables.rs:357:1:383:1 | exit main (normal) | | -| variables.rs:358:5:358:22 | PathExpr | variables.rs:358:5:358:24 | CallExpr | | -| variables.rs:358:5:358:24 | CallExpr | variables.rs:359:5:359:23 | ExprStmt | | -| variables.rs:358:5:358:25 | ExprStmt | variables.rs:358:5:358:22 | PathExpr | | -| variables.rs:359:5:359:20 | PathExpr | variables.rs:359:5:359:22 | CallExpr | | -| variables.rs:359:5:359:22 | CallExpr | variables.rs:360:5:360:23 | ExprStmt | | -| variables.rs:359:5:359:23 | ExprStmt | variables.rs:359:5:359:20 | PathExpr | | -| variables.rs:360:5:360:20 | PathExpr | variables.rs:360:5:360:22 | CallExpr | | -| variables.rs:360:5:360:22 | CallExpr | variables.rs:361:5:361:23 | ExprStmt | | -| variables.rs:360:5:360:23 | ExprStmt | variables.rs:360:5:360:20 | PathExpr | | -| variables.rs:361:5:361:20 | PathExpr | variables.rs:361:5:361:22 | CallExpr | | -| variables.rs:361:5:361:22 | CallExpr | variables.rs:362:5:362:19 | ExprStmt | | -| variables.rs:361:5:361:23 | ExprStmt | variables.rs:361:5:361:20 | PathExpr | | -| variables.rs:362:5:362:16 | PathExpr | variables.rs:362:5:362:18 | CallExpr | | -| variables.rs:362:5:362:18 | CallExpr | variables.rs:363:5:363:19 | ExprStmt | | -| variables.rs:362:5:362:19 | ExprStmt | variables.rs:362:5:362:16 | PathExpr | | -| variables.rs:363:5:363:16 | PathExpr | variables.rs:363:5:363:18 | CallExpr | | -| variables.rs:363:5:363:18 | CallExpr | variables.rs:364:5:364:19 | ExprStmt | | -| variables.rs:363:5:363:19 | ExprStmt | variables.rs:363:5:363:16 | PathExpr | | -| variables.rs:364:5:364:16 | PathExpr | variables.rs:364:5:364:18 | CallExpr | | -| variables.rs:364:5:364:18 | CallExpr | variables.rs:365:5:365:19 | ExprStmt | | -| variables.rs:364:5:364:19 | ExprStmt | variables.rs:364:5:364:16 | PathExpr | | -| variables.rs:365:5:365:16 | PathExpr | variables.rs:365:5:365:18 | CallExpr | | -| variables.rs:365:5:365:18 | CallExpr | variables.rs:366:5:366:21 | ExprStmt | | -| variables.rs:365:5:365:19 | ExprStmt | variables.rs:365:5:365:16 | PathExpr | | -| variables.rs:366:5:366:18 | PathExpr | variables.rs:366:5:366:20 | CallExpr | | -| variables.rs:366:5:366:20 | CallExpr | variables.rs:367:5:367:21 | ExprStmt | | -| variables.rs:366:5:366:21 | ExprStmt | variables.rs:366:5:366:18 | PathExpr | | -| variables.rs:367:5:367:18 | PathExpr | variables.rs:367:5:367:20 | CallExpr | | -| variables.rs:367:5:367:20 | CallExpr | variables.rs:368:5:368:21 | ExprStmt | | -| variables.rs:367:5:367:21 | ExprStmt | variables.rs:367:5:367:18 | PathExpr | | -| variables.rs:368:5:368:18 | PathExpr | variables.rs:368:5:368:20 | CallExpr | | -| variables.rs:368:5:368:20 | CallExpr | variables.rs:369:5:369:21 | ExprStmt | | -| variables.rs:368:5:368:21 | ExprStmt | variables.rs:368:5:368:18 | PathExpr | | -| variables.rs:369:5:369:18 | PathExpr | variables.rs:369:5:369:20 | CallExpr | | -| variables.rs:369:5:369:20 | CallExpr | variables.rs:370:5:370:21 | ExprStmt | | -| variables.rs:369:5:369:21 | ExprStmt | variables.rs:369:5:369:18 | PathExpr | | -| variables.rs:370:5:370:18 | PathExpr | variables.rs:370:5:370:20 | CallExpr | | -| variables.rs:370:5:370:20 | CallExpr | variables.rs:371:5:371:21 | ExprStmt | | -| variables.rs:370:5:370:21 | ExprStmt | variables.rs:370:5:370:18 | PathExpr | | -| variables.rs:371:5:371:18 | PathExpr | variables.rs:371:5:371:20 | CallExpr | | -| variables.rs:371:5:371:20 | CallExpr | variables.rs:372:5:372:21 | ExprStmt | | -| variables.rs:371:5:371:21 | ExprStmt | variables.rs:371:5:371:18 | PathExpr | | -| variables.rs:372:5:372:18 | PathExpr | variables.rs:372:5:372:20 | CallExpr | | -| variables.rs:372:5:372:20 | CallExpr | variables.rs:373:5:373:21 | ExprStmt | | -| variables.rs:372:5:372:21 | ExprStmt | variables.rs:372:5:372:18 | PathExpr | | -| variables.rs:373:5:373:18 | PathExpr | variables.rs:373:5:373:20 | CallExpr | | -| variables.rs:373:5:373:20 | CallExpr | variables.rs:374:5:374:21 | ExprStmt | | -| variables.rs:373:5:373:21 | ExprStmt | variables.rs:373:5:373:18 | PathExpr | | -| variables.rs:374:5:374:18 | PathExpr | variables.rs:374:5:374:20 | CallExpr | | -| variables.rs:374:5:374:20 | CallExpr | variables.rs:375:5:375:36 | ExprStmt | | -| variables.rs:374:5:374:21 | ExprStmt | variables.rs:374:5:374:18 | PathExpr | | -| variables.rs:375:5:375:18 | PathExpr | variables.rs:375:20:375:22 | "a" | | -| variables.rs:375:5:375:35 | CallExpr | variables.rs:376:5:376:37 | ExprStmt | | -| variables.rs:375:5:375:36 | ExprStmt | variables.rs:375:5:375:18 | PathExpr | | -| variables.rs:375:20:375:22 | "a" | variables.rs:375:26:375:28 | "b" | | -| variables.rs:375:25:375:34 | TupleExpr | variables.rs:375:5:375:35 | CallExpr | | -| variables.rs:375:26:375:28 | "b" | variables.rs:375:31:375:33 | "c" | | -| variables.rs:375:31:375:33 | "c" | variables.rs:375:25:375:34 | TupleExpr | | -| variables.rs:376:5:376:18 | PathExpr | variables.rs:376:20:376:31 | PathExpr | | -| variables.rs:376:5:376:36 | CallExpr | variables.rs:377:5:377:26 | ExprStmt | | -| variables.rs:376:5:376:37 | ExprStmt | variables.rs:376:5:376:18 | PathExpr | | -| variables.rs:376:20:376:31 | PathExpr | variables.rs:376:33:376:34 | 45 | | -| variables.rs:376:20:376:35 | CallExpr | variables.rs:376:5:376:36 | CallExpr | | -| variables.rs:376:33:376:34 | 45 | variables.rs:376:20:376:35 | CallExpr | | -| variables.rs:377:5:377:23 | PathExpr | variables.rs:377:5:377:25 | CallExpr | | -| variables.rs:377:5:377:25 | CallExpr | variables.rs:378:5:378:23 | ExprStmt | | -| variables.rs:377:5:377:26 | ExprStmt | variables.rs:377:5:377:23 | PathExpr | | +| variables.rs:357:1:363:1 | enter alias | variables.rs:358:5:358:18 | LetStmt | | +| variables.rs:357:1:363:1 | exit alias (normal) | variables.rs:357:1:363:1 | exit alias | | +| variables.rs:357:12:363:1 | BlockExpr | variables.rs:357:1:363:1 | exit alias (normal) | | +| variables.rs:358:5:358:18 | LetStmt | variables.rs:358:17:358:17 | 1 | | +| variables.rs:358:9:358:13 | x | variables.rs:359:5:360:15 | LetStmt | match, no-match | +| variables.rs:358:17:358:17 | 1 | variables.rs:358:9:358:13 | x | | +| variables.rs:359:5:360:15 | LetStmt | variables.rs:360:14:360:14 | x | | +| variables.rs:359:9:359:9 | y | variables.rs:361:5:361:11 | ExprStmt | match, no-match | +| variables.rs:360:9:360:14 | RefExpr | variables.rs:359:9:359:9 | y | | +| variables.rs:360:14:360:14 | x | variables.rs:360:9:360:14 | RefExpr | | +| variables.rs:361:5:361:6 | * ... | variables.rs:361:10:361:10 | 2 | | +| variables.rs:361:5:361:10 | ... = ... | variables.rs:362:5:362:17 | ExprStmt | | +| variables.rs:361:5:361:11 | ExprStmt | variables.rs:361:6:361:6 | y | | +| variables.rs:361:6:361:6 | y | variables.rs:361:5:361:6 | * ... | | +| variables.rs:361:10:361:10 | 2 | variables.rs:361:5:361:10 | ... = ... | | +| variables.rs:362:5:362:13 | PathExpr | variables.rs:362:15:362:15 | x | | +| variables.rs:362:5:362:16 | CallExpr | variables.rs:357:12:363:1 | BlockExpr | | +| variables.rs:362:5:362:17 | ExprStmt | variables.rs:362:5:362:13 | PathExpr | | +| variables.rs:362:15:362:15 | x | variables.rs:362:5:362:16 | CallExpr | | +| variables.rs:365:1:373:1 | enter capture | variables.rs:366:5:366:19 | LetStmt | | +| variables.rs:365:1:373:1 | exit capture (normal) | variables.rs:365:1:373:1 | exit capture | | +| variables.rs:365:14:373:1 | BlockExpr | variables.rs:365:1:373:1 | exit capture (normal) | | +| variables.rs:366:5:366:19 | LetStmt | variables.rs:366:17:366:18 | 10 | | +| variables.rs:366:9:366:13 | x | variables.rs:367:5:370:6 | LetStmt | match, no-match | +| variables.rs:366:17:366:18 | 10 | variables.rs:366:9:366:13 | x | | +| variables.rs:367:5:370:6 | LetStmt | variables.rs:367:19:370:5 | ClosureExpr | | +| variables.rs:367:9:367:15 | cap | variables.rs:371:5:371:10 | ExprStmt | match, no-match | +| variables.rs:367:19:370:5 | ClosureExpr | variables.rs:367:9:367:15 | cap | | +| variables.rs:367:19:370:5 | enter ClosureExpr | variables.rs:368:9:368:21 | ExprStmt | | +| variables.rs:367:19:370:5 | exit ClosureExpr (normal) | variables.rs:367:19:370:5 | exit ClosureExpr | | +| variables.rs:367:22:370:5 | BlockExpr | variables.rs:367:19:370:5 | exit ClosureExpr (normal) | | +| variables.rs:368:9:368:17 | PathExpr | variables.rs:368:19:368:19 | x | | +| variables.rs:368:9:368:20 | CallExpr | variables.rs:369:9:369:15 | ExprStmt | | +| variables.rs:368:9:368:21 | ExprStmt | variables.rs:368:9:368:17 | PathExpr | | +| variables.rs:368:19:368:19 | x | variables.rs:368:9:368:20 | CallExpr | | +| variables.rs:369:9:369:9 | x | variables.rs:369:14:369:14 | 1 | | +| variables.rs:369:9:369:14 | ... += ... | variables.rs:367:22:370:5 | BlockExpr | | +| variables.rs:369:9:369:15 | ExprStmt | variables.rs:369:9:369:9 | x | | +| variables.rs:369:14:369:14 | 1 | variables.rs:369:9:369:14 | ... += ... | | +| variables.rs:371:5:371:7 | cap | variables.rs:371:5:371:9 | CallExpr | | +| variables.rs:371:5:371:9 | CallExpr | variables.rs:372:5:372:17 | ExprStmt | | +| variables.rs:371:5:371:10 | ExprStmt | variables.rs:371:5:371:7 | cap | | +| variables.rs:372:5:372:13 | PathExpr | variables.rs:372:15:372:15 | x | | +| variables.rs:372:5:372:16 | CallExpr | variables.rs:365:14:373:1 | BlockExpr | | +| variables.rs:372:5:372:17 | ExprStmt | variables.rs:372:5:372:13 | PathExpr | | +| variables.rs:372:15:372:15 | x | variables.rs:372:5:372:16 | CallExpr | | +| variables.rs:375:1:403:1 | enter main | variables.rs:376:5:376:25 | ExprStmt | | +| variables.rs:375:1:403:1 | exit main (normal) | variables.rs:375:1:403:1 | exit main | | +| variables.rs:375:11:403:1 | BlockExpr | variables.rs:375:1:403:1 | exit main (normal) | | +| variables.rs:376:5:376:22 | PathExpr | variables.rs:376:5:376:24 | CallExpr | | +| variables.rs:376:5:376:24 | CallExpr | variables.rs:377:5:377:23 | ExprStmt | | +| variables.rs:376:5:376:25 | ExprStmt | variables.rs:376:5:376:22 | PathExpr | | +| variables.rs:377:5:377:20 | PathExpr | variables.rs:377:5:377:22 | CallExpr | | +| variables.rs:377:5:377:22 | CallExpr | variables.rs:378:5:378:23 | ExprStmt | | +| variables.rs:377:5:377:23 | ExprStmt | variables.rs:377:5:377:20 | PathExpr | | | variables.rs:378:5:378:20 | PathExpr | variables.rs:378:5:378:22 | CallExpr | | -| variables.rs:378:5:378:22 | CallExpr | variables.rs:379:5:379:19 | ExprStmt | | +| variables.rs:378:5:378:22 | CallExpr | variables.rs:379:5:379:23 | ExprStmt | | | variables.rs:378:5:378:23 | ExprStmt | variables.rs:378:5:378:20 | PathExpr | | -| variables.rs:379:5:379:16 | PathExpr | variables.rs:379:5:379:18 | CallExpr | | -| variables.rs:379:5:379:18 | CallExpr | variables.rs:380:5:380:17 | ExprStmt | | -| variables.rs:379:5:379:19 | ExprStmt | variables.rs:379:5:379:16 | PathExpr | | -| variables.rs:380:5:380:14 | PathExpr | variables.rs:380:5:380:16 | CallExpr | | -| variables.rs:380:5:380:16 | CallExpr | variables.rs:381:5:381:13 | ExprStmt | | -| variables.rs:380:5:380:17 | ExprStmt | variables.rs:380:5:380:14 | PathExpr | | -| variables.rs:381:5:381:10 | PathExpr | variables.rs:381:5:381:12 | CallExpr | | -| variables.rs:381:5:381:12 | CallExpr | variables.rs:382:5:382:17 | ExprStmt | | -| variables.rs:381:5:381:13 | ExprStmt | variables.rs:381:5:381:10 | PathExpr | | -| variables.rs:382:5:382:14 | PathExpr | variables.rs:382:5:382:16 | CallExpr | | -| variables.rs:382:5:382:16 | CallExpr | variables.rs:357:11:383:1 | BlockExpr | | -| variables.rs:382:5:382:17 | ExprStmt | variables.rs:382:5:382:14 | PathExpr | | +| variables.rs:379:5:379:20 | PathExpr | variables.rs:379:5:379:22 | CallExpr | | +| variables.rs:379:5:379:22 | CallExpr | variables.rs:380:5:380:19 | ExprStmt | | +| variables.rs:379:5:379:23 | ExprStmt | variables.rs:379:5:379:20 | PathExpr | | +| variables.rs:380:5:380:16 | PathExpr | variables.rs:380:5:380:18 | CallExpr | | +| variables.rs:380:5:380:18 | CallExpr | variables.rs:381:5:381:19 | ExprStmt | | +| variables.rs:380:5:380:19 | ExprStmt | variables.rs:380:5:380:16 | PathExpr | | +| variables.rs:381:5:381:16 | PathExpr | variables.rs:381:5:381:18 | CallExpr | | +| variables.rs:381:5:381:18 | CallExpr | variables.rs:382:5:382:19 | ExprStmt | | +| variables.rs:381:5:381:19 | ExprStmt | variables.rs:381:5:381:16 | PathExpr | | +| variables.rs:382:5:382:16 | PathExpr | variables.rs:382:5:382:18 | CallExpr | | +| variables.rs:382:5:382:18 | CallExpr | variables.rs:383:5:383:19 | ExprStmt | | +| variables.rs:382:5:382:19 | ExprStmt | variables.rs:382:5:382:16 | PathExpr | | +| variables.rs:383:5:383:16 | PathExpr | variables.rs:383:5:383:18 | CallExpr | | +| variables.rs:383:5:383:18 | CallExpr | variables.rs:384:5:384:21 | ExprStmt | | +| variables.rs:383:5:383:19 | ExprStmt | variables.rs:383:5:383:16 | PathExpr | | +| variables.rs:384:5:384:18 | PathExpr | variables.rs:384:5:384:20 | CallExpr | | +| variables.rs:384:5:384:20 | CallExpr | variables.rs:385:5:385:21 | ExprStmt | | +| variables.rs:384:5:384:21 | ExprStmt | variables.rs:384:5:384:18 | PathExpr | | +| variables.rs:385:5:385:18 | PathExpr | variables.rs:385:5:385:20 | CallExpr | | +| variables.rs:385:5:385:20 | CallExpr | variables.rs:386:5:386:21 | ExprStmt | | +| variables.rs:385:5:385:21 | ExprStmt | variables.rs:385:5:385:18 | PathExpr | | +| variables.rs:386:5:386:18 | PathExpr | variables.rs:386:5:386:20 | CallExpr | | +| variables.rs:386:5:386:20 | CallExpr | variables.rs:387:5:387:21 | ExprStmt | | +| variables.rs:386:5:386:21 | ExprStmt | variables.rs:386:5:386:18 | PathExpr | | +| variables.rs:387:5:387:18 | PathExpr | variables.rs:387:5:387:20 | CallExpr | | +| variables.rs:387:5:387:20 | CallExpr | variables.rs:388:5:388:21 | ExprStmt | | +| variables.rs:387:5:387:21 | ExprStmt | variables.rs:387:5:387:18 | PathExpr | | +| variables.rs:388:5:388:18 | PathExpr | variables.rs:388:5:388:20 | CallExpr | | +| variables.rs:388:5:388:20 | CallExpr | variables.rs:389:5:389:21 | ExprStmt | | +| variables.rs:388:5:388:21 | ExprStmt | variables.rs:388:5:388:18 | PathExpr | | +| variables.rs:389:5:389:18 | PathExpr | variables.rs:389:5:389:20 | CallExpr | | +| variables.rs:389:5:389:20 | CallExpr | variables.rs:390:5:390:21 | ExprStmt | | +| variables.rs:389:5:389:21 | ExprStmt | variables.rs:389:5:389:18 | PathExpr | | +| variables.rs:390:5:390:18 | PathExpr | variables.rs:390:5:390:20 | CallExpr | | +| variables.rs:390:5:390:20 | CallExpr | variables.rs:391:5:391:21 | ExprStmt | | +| variables.rs:390:5:390:21 | ExprStmt | variables.rs:390:5:390:18 | PathExpr | | +| variables.rs:391:5:391:18 | PathExpr | variables.rs:391:5:391:20 | CallExpr | | +| variables.rs:391:5:391:20 | CallExpr | variables.rs:392:5:392:21 | ExprStmt | | +| variables.rs:391:5:391:21 | ExprStmt | variables.rs:391:5:391:18 | PathExpr | | +| variables.rs:392:5:392:18 | PathExpr | variables.rs:392:5:392:20 | CallExpr | | +| variables.rs:392:5:392:20 | CallExpr | variables.rs:393:5:393:36 | ExprStmt | | +| variables.rs:392:5:392:21 | ExprStmt | variables.rs:392:5:392:18 | PathExpr | | +| variables.rs:393:5:393:18 | PathExpr | variables.rs:393:20:393:22 | "a" | | +| variables.rs:393:5:393:35 | CallExpr | variables.rs:394:5:394:37 | ExprStmt | | +| variables.rs:393:5:393:36 | ExprStmt | variables.rs:393:5:393:18 | PathExpr | | +| variables.rs:393:20:393:22 | "a" | variables.rs:393:26:393:28 | "b" | | +| variables.rs:393:25:393:34 | TupleExpr | variables.rs:393:5:393:35 | CallExpr | | +| variables.rs:393:26:393:28 | "b" | variables.rs:393:31:393:33 | "c" | | +| variables.rs:393:31:393:33 | "c" | variables.rs:393:25:393:34 | TupleExpr | | +| variables.rs:394:5:394:18 | PathExpr | variables.rs:394:20:394:31 | PathExpr | | +| variables.rs:394:5:394:36 | CallExpr | variables.rs:395:5:395:26 | ExprStmt | | +| variables.rs:394:5:394:37 | ExprStmt | variables.rs:394:5:394:18 | PathExpr | | +| variables.rs:394:20:394:31 | PathExpr | variables.rs:394:33:394:34 | 45 | | +| variables.rs:394:20:394:35 | CallExpr | variables.rs:394:5:394:36 | CallExpr | | +| variables.rs:394:33:394:34 | 45 | variables.rs:394:20:394:35 | CallExpr | | +| variables.rs:395:5:395:23 | PathExpr | variables.rs:395:5:395:25 | CallExpr | | +| variables.rs:395:5:395:25 | CallExpr | variables.rs:396:5:396:23 | ExprStmt | | +| variables.rs:395:5:395:26 | ExprStmt | variables.rs:395:5:395:23 | PathExpr | | +| variables.rs:396:5:396:20 | PathExpr | variables.rs:396:5:396:22 | CallExpr | | +| variables.rs:396:5:396:22 | CallExpr | variables.rs:397:5:397:19 | ExprStmt | | +| variables.rs:396:5:396:23 | ExprStmt | variables.rs:396:5:396:20 | PathExpr | | +| variables.rs:397:5:397:16 | PathExpr | variables.rs:397:5:397:18 | CallExpr | | +| variables.rs:397:5:397:18 | CallExpr | variables.rs:398:5:398:17 | ExprStmt | | +| variables.rs:397:5:397:19 | ExprStmt | variables.rs:397:5:397:16 | PathExpr | | +| variables.rs:398:5:398:14 | PathExpr | variables.rs:398:5:398:16 | CallExpr | | +| variables.rs:398:5:398:16 | CallExpr | variables.rs:399:5:399:13 | ExprStmt | | +| variables.rs:398:5:398:17 | ExprStmt | variables.rs:398:5:398:14 | PathExpr | | +| variables.rs:399:5:399:10 | PathExpr | variables.rs:399:5:399:12 | CallExpr | | +| variables.rs:399:5:399:12 | CallExpr | variables.rs:400:5:400:17 | ExprStmt | | +| variables.rs:399:5:399:13 | ExprStmt | variables.rs:399:5:399:10 | PathExpr | | +| variables.rs:400:5:400:14 | PathExpr | variables.rs:400:5:400:16 | CallExpr | | +| variables.rs:400:5:400:16 | CallExpr | variables.rs:401:5:401:12 | ExprStmt | | +| variables.rs:400:5:400:17 | ExprStmt | variables.rs:400:5:400:14 | PathExpr | | +| variables.rs:401:5:401:9 | PathExpr | variables.rs:401:5:401:11 | CallExpr | | +| variables.rs:401:5:401:11 | CallExpr | variables.rs:402:5:402:14 | ExprStmt | | +| variables.rs:401:5:401:12 | ExprStmt | variables.rs:401:5:401:9 | PathExpr | | +| variables.rs:402:5:402:11 | PathExpr | variables.rs:402:5:402:13 | CallExpr | | +| variables.rs:402:5:402:13 | CallExpr | variables.rs:375:11:403:1 | BlockExpr | | +| variables.rs:402:5:402:14 | ExprStmt | variables.rs:402:5:402:11 | PathExpr | | breakTarget continueTarget diff --git a/rust/ql/test/library-tests/variables/variables.expected b/rust/ql/test/library-tests/variables/variables.expected index ccc1cd6072be..09430b5497c0 100644 --- a/rust/ql/test/library-tests/variables/variables.expected +++ b/rust/ql/test/library-tests/variables/variables.expected @@ -72,6 +72,10 @@ variable | variables.rs:339:9:339:13 | ref_i | | variables.rs:345:17:345:17 | x | | variables.rs:352:13:352:13 | x | +| variables.rs:358:13:358:13 | x | +| variables.rs:359:9:359:9 | y | +| variables.rs:366:13:366:13 | x | +| variables.rs:367:13:367:15 | cap | variableAccess | variables.rs:13:15:13:16 | x1 | variables.rs:12:9:12:10 | x1 | | variables.rs:18:15:18:16 | x2 | variables.rs:17:13:17:14 | x2 | @@ -167,6 +171,13 @@ variableAccess | variables.rs:348:10:348:10 | x | variables.rs:345:17:345:17 | x | | variables.rs:353:23:353:23 | x | variables.rs:352:13:352:13 | x | | variables.rs:354:15:354:15 | x | variables.rs:352:13:352:13 | x | +| variables.rs:360:14:360:14 | x | variables.rs:358:13:358:13 | x | +| variables.rs:361:6:361:6 | y | variables.rs:359:9:359:9 | y | +| variables.rs:362:15:362:15 | x | variables.rs:358:13:358:13 | x | +| variables.rs:368:19:368:19 | x | variables.rs:366:13:366:13 | x | +| variables.rs:369:9:369:9 | x | variables.rs:366:13:366:13 | x | +| variables.rs:371:5:371:7 | cap | variables.rs:367:13:367:15 | cap | +| variables.rs:372:15:372:15 | x | variables.rs:366:13:366:13 | x | variableWriteAccess | variables.rs:19:5:19:6 | x2 | variables.rs:17:13:17:14 | x2 | | variables.rs:277:9:277:10 | c2 | variables.rs:270:13:270:14 | c2 | @@ -259,6 +270,11 @@ variableReadAccess | variables.rs:347:10:347:10 | x | variables.rs:345:17:345:17 | x | | variables.rs:348:10:348:10 | x | variables.rs:345:17:345:17 | x | | variables.rs:354:15:354:15 | x | variables.rs:352:13:352:13 | x | +| variables.rs:361:6:361:6 | y | variables.rs:359:9:359:9 | y | +| variables.rs:362:15:362:15 | x | variables.rs:358:13:358:13 | x | +| variables.rs:368:19:368:19 | x | variables.rs:366:13:366:13 | x | +| variables.rs:371:5:371:7 | cap | variables.rs:367:13:367:15 | cap | +| variables.rs:372:15:372:15 | x | variables.rs:366:13:366:13 | x | variableInitializer | variables.rs:12:9:12:10 | x1 | variables.rs:12:14:12:16 | "a" | | variables.rs:17:13:17:14 | x2 | variables.rs:17:18:17:18 | 4 | @@ -288,3 +304,12 @@ variableInitializer | variables.rs:338:13:338:13 | i | variables.rs:338:17:338:17 | 1 | | variables.rs:339:9:339:13 | ref_i | variables.rs:340:9:340:14 | RefExpr | | variables.rs:352:13:352:13 | x | variables.rs:352:17:352:17 | 2 | +| variables.rs:358:13:358:13 | x | variables.rs:358:17:358:17 | 1 | +| variables.rs:359:9:359:9 | y | variables.rs:360:9:360:14 | RefExpr | +| variables.rs:366:13:366:13 | x | variables.rs:366:17:366:18 | 10 | +| variables.rs:367:13:367:15 | cap | variables.rs:367:19:370:5 | ClosureExpr | +capturedVariable +| variables.rs:366:13:366:13 | x | +capturedAccess +| variables.rs:368:19:368:19 | x | +| variables.rs:369:9:369:9 | x | diff --git a/rust/ql/test/library-tests/variables/variables.ql b/rust/ql/test/library-tests/variables/variables.ql index 9657c361fd59..23eab9774457 100644 --- a/rust/ql/test/library-tests/variables/variables.ql +++ b/rust/ql/test/library-tests/variables/variables.ql @@ -11,6 +11,10 @@ query predicate variableReadAccess(VariableReadAccess va, Variable v) { v = va.g query predicate variableInitializer(Variable v, Expr e) { e = v.getInitializer() } +query predicate capturedVariable(Variable v) { v.isCaptured() } + +query predicate capturedAccess(VariableAccess va) { va.isCapture() } + module VariableAccessTest implements TestSig { string getARelevantTag() { result = ["", "write_", "read_"] + "access" } diff --git a/rust/ql/test/library-tests/variables/variables.rs b/rust/ql/test/library-tests/variables/variables.rs index 52c5288a6b32..bf3491dff613 100644 --- a/rust/ql/test/library-tests/variables/variables.rs +++ b/rust/ql/test/library-tests/variables/variables.rs @@ -354,6 +354,24 @@ fn mutate_arg() { print_i64(x); // $ read_access=x } +fn alias() { + let mut x = 1; // x + let y = // y + &mut x; // $ access=x + *y = 2; // $ read_access=y + print_i64(x); // $ read_access=x +} + +fn capture() { + let mut x = 10; // x + let mut cap = || { + print_i64(x); // $ read_access=x + x += 1; // $ access=x + }; + cap(); // $ read_access=cap + print_i64(x); // $ read_access=x +} + fn main() { immutable_variable(); mutable_variable(); @@ -380,4 +398,6 @@ fn main() { add_assign(); mutate(); mutate_arg(); + alias(); + capture(); } diff --git a/shared/util/codeql/util/DenseRank.qll b/shared/util/codeql/util/DenseRank.qll new file mode 100644 index 000000000000..d1ba4ae4b62c --- /dev/null +++ b/shared/util/codeql/util/DenseRank.qll @@ -0,0 +1,131 @@ +/** + * Provides modules for computing dense `rank`s. See the `DenseRank` module + * below for a more detailed explanation. + */ + +/** Provides the input to `DenseRank`. */ +signature module DenseRankInputSig { + /** An element that is ranked. */ + bindingset[this] + class Ranked; + + /** Gets the rank of `r`. */ + int getRank(Ranked r); +} + +/** + * Provides the `denseRank` predicate for computing dense `rank`s. For example, + * if we have + * + * ```ql + * query predicate names(string name) { + * name = ["Alice", "Bob", "Charles", "Charlie", "David"] + * } + * + * int rankByFirstLetter(string name) { + * name = rank[result](string n | names(n) | n order by n.charAt(0)) + * } + * ``` + * + * then `rankByFirstLetter` computes the following relation + * + * ``` + * Alice 1 + * Bob 2 + * Charles 3 + * Charlie 3 + * David 5 + * ``` + * + * Note that `"David"` has rank 5 instead of 4. If we want a dense ranking instead, + * we can do + * + * ```ql + * module M implements DenseRankInputSig { + * class Ranked = string; + * + * predicate getRank = rankByFirstLetter/1; + * } + * + * predicate denseRank = DenseRank::denseRank/1; + * ``` + */ +module DenseRank { + private import Input + + private int rankRank(Ranked r, int rnk) { + rnk = getRank(r) and + rnk = rank[result](int rnk0 | rnk0 = getRank(_) | rnk0) + } + + /** Gets the dense rank of `r`. */ + int denseRank(Ranked r) { result = rankRank(r, getRank(r)) } +} + +/** Provides the input to `DenseRank2`. */ +signature module DenseRankInputSig2 { + /** A ranking context. */ + bindingset[this] + class C; + + /** An element that is ranked. */ + bindingset[this] + class Ranked; + + /** Gets the rank of `r` in the context provided by `c`. */ + int getRank(C c, Ranked r); +} + +/** Same as `DenseRank`, but allows for a context consisting of one element. */ +module DenseRank2 { + private import Input + + private int rankRank(C c, Ranked r, int rnk) { + rnk = getRank(c, r) and + rnk = rank[result](int rnk0 | rnk0 = getRank(c, _) | rnk0) + } + + /** Gets the dense rank of `r` in the context provided by `c`. */ + int denseRank(C c, Ranked r) { + exists(int rnk | + result = rankRank(c, r, rnk) and + rnk = getRank(c, r) + ) + } +} + +/** Provides the input to `DenseRank3`. */ +signature module DenseRankInputSig3 { + /** A ranking context. */ + bindingset[this] + class C1; + + /** A ranking context. */ + bindingset[this] + class C2; + + /** An element that is ranked. */ + bindingset[this] + class Ranked; + + /** Gets the rank of `r` in the context provided by `c1` and `c2`. */ + int getRank(C1 c1, C2 c2, Ranked r); +} + +/** Same as `DenseRank`, but allows for a context consisting of two elements. */ +module DenseRank3 { + private import Input + + private int rankRank(C1 c1, C2 c2, Ranked r, int rnk) { + rnk = getRank(c1, c2, r) and + rnk = rank[result](int rnk0 | rnk0 = getRank(c1, c2, _) | rnk0) + } + + /** Gets the dense rank of `r` in the context provided by `c1` and `c2`. */ + int denseRank(C1 c1, C2 c2, Ranked r) { + exists(int rnk | + result = rankRank(c1, c2, r, rnk) and + rnk = getRank(c1, c2, r) + ) + } +}