From 4b161572933bc23d006f26259541602db70b0e23 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 22 Nov 2024 10:30:33 +0100 Subject: [PATCH 1/4] Rust: Use extended canonical paths to resolve calls in data flow --- .../rust/dataflow/internal/DataFlowImpl.qll | 54 ++++++++++++++++--- shared/util/codeql/util/Option.qll | 1 + 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll index 1ec8a42ee7e0..3710004b8de6 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll @@ -399,13 +399,55 @@ module RustDataFlow implements InputSig { final class ReturnKind = ReturnKindAlias; + private import codeql.util.Option + + private class CrateOrigin extends string { + CrateOrigin() { + this = [any(Item i).getCrateOrigin(), any(Resolvable r).getResolvedCrateOrigin()] + } + } + + private class CrateOriginOption = Option::Option; + + pragma[nomagic] + private predicate hasExtendedCanonicalPath( + DataFlowCallable c, CrateOriginOption crate, string path + ) { + exists(Item i | + i = c.asCfgScope() and + path = i.getExtendedCanonicalPath() + | + crate.asSome() = i.getCrateOrigin() + or + crate.isNone() and + not i.hasCrateOrigin() + ) + } + + pragma[nomagic] + private predicate resolvesExtendedCanonicalPath( + DataFlowCall c, CrateOriginOption crate, string path + ) { + exists(Resolvable r | + path = r.getResolvedPath() and + ( + r = c.asMethodCallExprCfgNode().getExpr() + or + r = c.asCallExprCfgNode().getExpr().(PathExprCfgNode).getPath() + ) + | + crate.asSome() = r.getResolvedCrateOrigin() + or + crate.isNone() and + not r.hasResolvedCrateOrigin() + ) + } + /** Gets a viable implementation of the target of the given `Call`. */ - DataFlowCallable viableCallable(DataFlowCall c) { - exists(Function f, string name | result.asCfgScope() = f and name = f.getName().toString() | - if f.getParamList().hasSelfParam() - then name = c.asMethodCallExprCfgNode().getNameRef().getText() - else - name = c.asCallExprCfgNode().getExpr().getExpr().(PathExpr).getPath().getPart().toString() + DataFlowCallable viableCallable(DataFlowCall call) { + exists(string path, CrateOriginOption crate | + hasExtendedCanonicalPath(result, crate, path) and + resolvesExtendedCanonicalPath(call, crate, path) ) } diff --git a/shared/util/codeql/util/Option.qll b/shared/util/codeql/util/Option.qll index 31df747afe87..8ba4d8e840bc 100644 --- a/shared/util/codeql/util/Option.qll +++ b/shared/util/codeql/util/Option.qll @@ -2,6 +2,7 @@ /** A type with `toString`. */ private signature class TypeWithToString { + bindingset[this] string toString(); } From b52058ffed656575d5fc5bd4063672a849bbba00 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 22 Nov 2024 14:52:59 +0100 Subject: [PATCH 2/4] Rust: Add more flow tests --- .../dataflow/local/DataFlowStep.expected | 127 +++++++++++++----- .../test/library-tests/dataflow/local/main.rs | 101 ++++++++++---- 2 files changed, 165 insertions(+), 63 deletions(-) diff --git a/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected index 86bc28d7940b..433f38706457 100644 --- a/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -75,42 +75,95 @@ | main.rs:97:38:97:38 | p | main.rs:97:9:97:34 | RecordPat | | main.rs:104:9:104:10 | [SSA] s1 | main.rs:106:11:106:12 | s1 | | main.rs:104:9:104:10 | s1 | main.rs:104:9:104:10 | [SSA] s1 | -| main.rs:104:14:104:28 | CallExpr | main.rs:104:9:104:10 | s1 | +| main.rs:104:14:104:37 | CallExpr | main.rs:104:9:104:10 | s1 | | main.rs:105:9:105:10 | [SSA] s2 | main.rs:110:11:110:12 | s2 | | main.rs:105:9:105:10 | s2 | main.rs:105:9:105:10 | [SSA] s2 | -| main.rs:105:14:105:20 | CallExpr | main.rs:105:9:105:10 | s2 | -| main.rs:107:14:107:14 | [SSA] n | main.rs:107:25:107:25 | n | -| main.rs:107:14:107:14 | n | main.rs:107:14:107:14 | [SSA] n | -| main.rs:107:20:107:26 | CallExpr | main.rs:106:5:109:5 | MatchExpr | -| main.rs:108:17:108:23 | CallExpr | main.rs:106:5:109:5 | MatchExpr | -| main.rs:110:5:113:5 | MatchExpr | main.rs:103:27:114:1 | BlockExpr | -| main.rs:111:14:111:14 | [SSA] n | main.rs:111:25:111:25 | n | -| main.rs:111:14:111:14 | n | main.rs:111:14:111:14 | [SSA] n | -| main.rs:111:20:111:26 | CallExpr | main.rs:110:5:113:5 | MatchExpr | -| main.rs:112:17:112:23 | CallExpr | main.rs:110:5:113:5 | MatchExpr | -| main.rs:117:9:117:9 | [SSA] a | main.rs:118:5:118:5 | a | -| main.rs:117:9:117:9 | a | main.rs:117:9:117:9 | [SSA] a | -| main.rs:117:13:117:17 | BlockExpr | main.rs:117:9:117:9 | a | -| main.rs:117:15:117:15 | 0 | main.rs:117:13:117:17 | BlockExpr | -| main.rs:118:5:118:5 | a | main.rs:116:31:119:1 | BlockExpr | -| main.rs:121:22:121:22 | [SSA] b | main.rs:123:12:123:12 | b | -| main.rs:121:22:121:22 | b | main.rs:121:22:121:22 | [SSA] b | -| main.rs:121:22:121:28 | Param | main.rs:121:22:121:22 | b | -| main.rs:122:9:122:9 | [SSA] a | main.rs:128:5:128:5 | a | -| main.rs:122:9:122:9 | a | main.rs:122:9:122:9 | [SSA] a | -| main.rs:122:13:127:5 | BlockExpr | main.rs:122:9:122:9 | a | -| main.rs:124:13:124:26 | BreakExpr | main.rs:122:13:127:5 | BlockExpr | -| main.rs:124:26:124:26 | 1 | main.rs:124:13:124:26 | BreakExpr | -| main.rs:126:9:126:9 | 2 | main.rs:122:13:127:5 | BlockExpr | -| main.rs:128:5:128:5 | a | main.rs:121:38:129:1 | BlockExpr | -| main.rs:131:22:131:22 | [SSA] b | main.rs:133:12:133:12 | b | -| main.rs:131:22:131:22 | b | main.rs:131:22:131:22 | [SSA] b | -| main.rs:131:22:131:28 | Param | main.rs:131:22:131:22 | b | -| main.rs:132:9:132:9 | [SSA] a | main.rs:138:5:138:5 | a | -| main.rs:132:9:132:9 | a | main.rs:132:9:132:9 | [SSA] a | -| main.rs:132:13:137:5 | BlockExpr | main.rs:132:9:132:9 | a | -| main.rs:134:13:134:26 | BreakExpr | main.rs:132:13:137:5 | BlockExpr | -| main.rs:134:26:134:26 | 1 | main.rs:134:13:134:26 | BreakExpr | -| main.rs:136:9:136:22 | BreakExpr | main.rs:132:13:137:5 | BlockExpr | -| main.rs:136:22:136:22 | 2 | main.rs:136:9:136:22 | BreakExpr | -| main.rs:138:5:138:5 | a | main.rs:131:38:139:1 | BlockExpr | +| main.rs:105:14:105:28 | CallExpr | main.rs:105:9:105:10 | s2 | +| main.rs:107:22:107:22 | [SSA] n | main.rs:107:33:107:33 | n | +| main.rs:107:22:107:22 | n | main.rs:107:22:107:22 | [SSA] n | +| main.rs:107:28:107:34 | CallExpr | main.rs:106:5:109:5 | MatchExpr | +| main.rs:108:25:108:31 | CallExpr | main.rs:106:5:109:5 | MatchExpr | +| main.rs:110:5:113:5 | MatchExpr | main.rs:103:37:114:1 | BlockExpr | +| main.rs:111:22:111:22 | [SSA] n | main.rs:111:33:111:33 | n | +| main.rs:111:22:111:22 | n | main.rs:111:22:111:22 | [SSA] n | +| main.rs:111:28:111:34 | CallExpr | main.rs:110:5:113:5 | MatchExpr | +| main.rs:112:25:112:31 | CallExpr | main.rs:110:5:113:5 | MatchExpr | +| main.rs:117:9:117:10 | [SSA] s1 | main.rs:119:11:119:12 | s1 | +| main.rs:117:9:117:10 | s1 | main.rs:117:9:117:10 | [SSA] s1 | +| main.rs:117:14:117:29 | CallExpr | main.rs:117:9:117:10 | s1 | +| main.rs:118:9:118:10 | [SSA] s2 | main.rs:123:11:123:12 | s2 | +| main.rs:118:9:118:10 | s2 | main.rs:118:9:118:10 | [SSA] s2 | +| main.rs:118:14:118:20 | CallExpr | main.rs:118:9:118:10 | s2 | +| main.rs:120:14:120:14 | [SSA] n | main.rs:120:25:120:25 | n | +| main.rs:120:14:120:14 | n | main.rs:120:14:120:14 | [SSA] n | +| main.rs:120:20:120:26 | CallExpr | main.rs:119:5:122:5 | MatchExpr | +| main.rs:121:17:121:23 | CallExpr | main.rs:119:5:122:5 | MatchExpr | +| main.rs:123:5:126:5 | MatchExpr | main.rs:116:39:127:1 | BlockExpr | +| main.rs:124:14:124:14 | [SSA] n | main.rs:124:25:124:25 | n | +| main.rs:124:14:124:14 | n | main.rs:124:14:124:14 | [SSA] n | +| main.rs:124:20:124:26 | CallExpr | main.rs:123:5:126:5 | MatchExpr | +| main.rs:125:17:125:23 | CallExpr | main.rs:123:5:126:5 | MatchExpr | +| main.rs:135:9:135:10 | [SSA] s1 | main.rs:137:11:137:12 | s1 | +| main.rs:135:9:135:10 | s1 | main.rs:135:9:135:10 | [SSA] s1 | +| main.rs:135:14:135:34 | CallExpr | main.rs:135:9:135:10 | s1 | +| main.rs:136:9:136:10 | [SSA] s2 | main.rs:141:11:141:12 | s2 | +| main.rs:136:9:136:10 | s2 | main.rs:136:9:136:10 | [SSA] s2 | +| main.rs:136:14:136:25 | CallExpr | main.rs:136:9:136:10 | s2 | +| main.rs:138:19:138:19 | [SSA] n | main.rs:138:30:138:30 | n | +| main.rs:138:19:138:19 | n | main.rs:138:19:138:19 | [SSA] n | +| main.rs:138:25:138:31 | CallExpr | main.rs:137:5:140:5 | MatchExpr | +| main.rs:139:19:139:19 | [SSA] n | main.rs:139:30:139:30 | n | +| main.rs:139:19:139:19 | n | main.rs:139:19:139:19 | [SSA] n | +| main.rs:139:25:139:31 | CallExpr | main.rs:137:5:140:5 | MatchExpr | +| main.rs:141:5:144:5 | MatchExpr | main.rs:134:42:145:1 | BlockExpr | +| main.rs:142:19:142:19 | [SSA] n | main.rs:142:30:142:30 | n | +| main.rs:142:19:142:19 | n | main.rs:142:19:142:19 | [SSA] n | +| main.rs:142:25:142:31 | CallExpr | main.rs:141:5:144:5 | MatchExpr | +| main.rs:143:19:143:19 | [SSA] n | main.rs:143:30:143:30 | n | +| main.rs:143:19:143:19 | n | main.rs:143:19:143:19 | [SSA] n | +| main.rs:143:25:143:31 | CallExpr | main.rs:141:5:144:5 | MatchExpr | +| main.rs:150:9:150:10 | [SSA] s1 | main.rs:152:11:152:12 | s1 | +| main.rs:150:9:150:10 | s1 | main.rs:150:9:150:10 | [SSA] s1 | +| main.rs:150:14:150:26 | CallExpr | main.rs:150:9:150:10 | s1 | +| main.rs:151:9:151:10 | [SSA] s2 | main.rs:156:11:156:12 | s2 | +| main.rs:151:9:151:10 | s2 | main.rs:151:9:151:10 | [SSA] s2 | +| main.rs:151:14:151:17 | CallExpr | main.rs:151:9:151:10 | s2 | +| main.rs:153:11:153:11 | [SSA] n | main.rs:153:22:153:22 | n | +| main.rs:153:11:153:11 | n | main.rs:153:11:153:11 | [SSA] n | +| main.rs:153:17:153:23 | CallExpr | main.rs:152:5:155:5 | MatchExpr | +| main.rs:154:11:154:11 | [SSA] n | main.rs:154:22:154:22 | n | +| main.rs:154:11:154:11 | n | main.rs:154:11:154:11 | [SSA] n | +| main.rs:154:17:154:23 | CallExpr | main.rs:152:5:155:5 | MatchExpr | +| main.rs:156:5:159:5 | MatchExpr | main.rs:149:44:160:1 | BlockExpr | +| main.rs:157:11:157:11 | [SSA] n | main.rs:157:22:157:22 | n | +| main.rs:157:11:157:11 | n | main.rs:157:11:157:11 | [SSA] n | +| main.rs:157:17:157:23 | CallExpr | main.rs:156:5:159:5 | MatchExpr | +| main.rs:158:11:158:11 | [SSA] n | main.rs:158:22:158:22 | n | +| main.rs:158:11:158:11 | n | main.rs:158:11:158:11 | [SSA] n | +| main.rs:158:17:158:23 | CallExpr | main.rs:156:5:159:5 | MatchExpr | +| main.rs:163:9:163:9 | [SSA] a | main.rs:164:5:164:5 | a | +| main.rs:163:9:163:9 | a | main.rs:163:9:163:9 | [SSA] a | +| main.rs:163:13:163:17 | BlockExpr | main.rs:163:9:163:9 | a | +| main.rs:163:15:163:15 | 0 | main.rs:163:13:163:17 | BlockExpr | +| main.rs:164:5:164:5 | a | main.rs:162:31:165:1 | BlockExpr | +| main.rs:167:22:167:22 | [SSA] b | main.rs:169:12:169:12 | b | +| main.rs:167:22:167:22 | b | main.rs:167:22:167:22 | [SSA] b | +| main.rs:167:22:167:28 | Param | main.rs:167:22:167:22 | b | +| main.rs:168:9:168:9 | [SSA] a | main.rs:174:5:174:5 | a | +| main.rs:168:9:168:9 | a | main.rs:168:9:168:9 | [SSA] a | +| main.rs:168:13:173:5 | BlockExpr | main.rs:168:9:168:9 | a | +| main.rs:170:13:170:26 | BreakExpr | main.rs:168:13:173:5 | BlockExpr | +| main.rs:170:26:170:26 | 1 | main.rs:170:13:170:26 | BreakExpr | +| main.rs:172:9:172:9 | 2 | main.rs:168:13:173:5 | BlockExpr | +| main.rs:174:5:174:5 | a | main.rs:167:38:175:1 | BlockExpr | +| main.rs:177:22:177:22 | [SSA] b | main.rs:179:12:179:12 | b | +| main.rs:177:22:177:22 | b | main.rs:177:22:177:22 | [SSA] b | +| main.rs:177:22:177:28 | Param | main.rs:177:22:177:22 | b | +| main.rs:178:9:178:9 | [SSA] a | main.rs:184:5:184:5 | a | +| main.rs:178:9:178:9 | a | main.rs:178:9:178:9 | [SSA] a | +| main.rs:178:13:183:5 | BlockExpr | main.rs:178:9:178:9 | a | +| main.rs:180:13:180:26 | BreakExpr | main.rs:178:13:183:5 | BlockExpr | +| main.rs:180:26:180:26 | 1 | main.rs:180:13:180:26 | BreakExpr | +| main.rs:182:9:182:22 | BreakExpr | main.rs:178:13:183:5 | BlockExpr | +| main.rs:182:22:182:22 | 2 | main.rs:182:9:182:22 | BreakExpr | +| main.rs:184:5:184:5 | a | main.rs:177:38:185:1 | BlockExpr | diff --git a/rust/ql/test/library-tests/dataflow/local/main.rs b/rust/ql/test/library-tests/dataflow/local/main.rs index 50aa4fdb965e..9f31b08f680f 100644 --- a/rust/ql/test/library-tests/dataflow/local/main.rs +++ b/rust/ql/test/library-tests/dataflow/local/main.rs @@ -16,24 +16,24 @@ fn direct() { } fn variable_usage() { - let s = source(1); - sink(s); // $ hasValueFlow=1 + let s = source(2); + sink(s); // $ hasValueFlow=2 } fn if_expression(cond: bool) { - let a = source(1); + let a = source(3); let b = 2; let c = if cond { a } else { b }; - sink(c); // $ hasValueFlow=1 + sink(c); // $ hasValueFlow=3 } fn match_expression(m: Option) { - let a = source(1); + let a = source(4); let b = match m { Some(_) => a, None => 0, }; - sink(b); // $ hasValueFlow=1 + sink(b); // $ hasValueFlow=4 } fn loop_with_break() { @@ -42,29 +42,29 @@ fn loop_with_break() { }; sink(a); let b = loop { - break source(1); + break source(5); }; - sink(b); // $ hasValueFlow=1 + sink(b); // $ hasValueFlow=5 } fn assignment() { let mut i = 1; sink(i); - i = source(2); - sink(i); // $ hasValueFlow=2 + i = source(6); + sink(i); // $ hasValueFlow=6 } // ----------------------------------------------------------------------------- // Data flow through data structures by writing and reading fn box_deref() { - let i = Box::new(source(1)); - sink(*i); // $ MISSING: hasValueFlow=1 + let i = Box::new(source(7)); + sink(*i); // $ MISSING: hasValueFlow=7 } fn tuple() { - let a = (source(1), 2); - sink(a.0); // $ MISSING: hasValueFlow=1 + let a = (source(8), 2); + sink(a.0); // $ MISSING: hasValueFlow=8 sink(a.1); } @@ -76,13 +76,13 @@ struct Point { fn struct_field() { let p = Point { - x: source(1), + x: source(9), y: 2, - z: source(3), + z: source(10), }; - sink(p.x); // MISSING: hasValueFlow=1 + sink(p.x); // $ MISSING: hasValueFlow=9 sink(p.y); - sink(p.z); // MISSING: hasValueFlow=3 + sink(p.z); // $ MISSING: hasValueFlow=10 } // ----------------------------------------------------------------------------- @@ -90,21 +90,34 @@ fn struct_field() { fn struct_pattern_match() { let p = Point { - x: source(1), + x: source(11), y: 2, - z: source(3), + z: source(12), }; let Point { x: a, y: b, z: c } = p; - sink(a); // MISSING: hasValueFlow=1 + sink(a); // $ MISSING: hasValueFlow=11 sink(b); - sink(c); // MISSING: hasValueFlow=3 + sink(c); // $ MISSING: hasValueFlow=12 } -fn option_pattern_match() { - let s1 = Some(source(1)); +fn option_pattern_match_qualified() { + let s1 = Option::Some(source(13)); + let s2 = Option::Some(2); + match s1 { + Option::Some(n) => sink(n), // $ MISSING: hasValueFlow=13 + Option::None => sink(0), + } + match s2 { + Option::Some(n) => sink(n), + Option::None => sink(0), + } +} + +fn option_pattern_match_unqualified() { + let s1 = Some(source(14)); let s2 = Some(2); match s1 { - Some(n) => sink(n), // MISSING: hasValueFlow=3 + Some(n) => sink(n), // $ MISSING: hasValueFlow=14 None => sink(0), } match s2 { @@ -113,6 +126,39 @@ fn option_pattern_match() { } } +enum MyEnum { + A(i64), + B(i64), +} + +fn custom_enum_pattern_match_qualified() { + let s1 = MyEnum::A(source(15)); + let s2 = MyEnum::B(2); + match s1 { + MyEnum::A(n) => sink(n), // $ MISSING: hasValueFlow=15 + MyEnum::B(n) => sink(n), + } + match s2 { + MyEnum::A(n) => sink(n), + MyEnum::B(n) => sink(n), + } +} + +use crate::MyEnum::*; + +fn custom_enum_pattern_match_unqualified() { + let s1 = A(source(16)); + let s2 = B(2); + match s1 { + A(n) => sink(n), // $ MISSING: hasValueFlow=16 + B(n) => sink(n), + } + match s2 { + A(n) => sink(n), + B(n) => sink(n), + } +} + fn block_expression1() -> i64 { let a = { 0 }; a @@ -149,7 +195,10 @@ fn main() { tuple(); struct_field(); struct_pattern_match(); - option_pattern_match(); + option_pattern_match_qualified(); + option_pattern_match_unqualified(); + custom_enum_pattern_match_qualified(); + custom_enum_pattern_match_unqualified(); block_expression1(); block_expression2(true); block_expression3(true); From aeb7b469dd4b43c60657c3c0064a1adcff3b8823 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 22 Nov 2024 14:54:20 +0100 Subject: [PATCH 3/4] Rust: Do not print `unit` type in data flow --- .../rust/dataflow/internal/DataFlowImpl.qll | 4 +- .../dataflow/barrier/inline-flow.expected | 36 +++--- .../dataflow/global/inline-flow.expected | 122 +++++++++--------- .../dataflow/local/inline-flow.expected | 30 ++--- 4 files changed, 97 insertions(+), 95 deletions(-) diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll index 3710004b8de6..4e892e8d19c7 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll @@ -461,7 +461,9 @@ module RustDataFlow implements InputSig { // NOTE: For now we use the type `Unit` and do not benefit from type // information in the data flow analysis. - final class DataFlowType = Unit; + final class DataFlowType extends Unit { + string toString() { result = "" } + } predicate compatibleTypes(DataFlowType t1, DataFlowType t2) { any() } diff --git a/rust/ql/test/library-tests/dataflow/barrier/inline-flow.expected b/rust/ql/test/library-tests/dataflow/barrier/inline-flow.expected index dd98dd9cee47..2e9b53dbaf19 100644 --- a/rust/ql/test/library-tests/dataflow/barrier/inline-flow.expected +++ b/rust/ql/test/library-tests/dataflow/barrier/inline-flow.expected @@ -1,29 +1,29 @@ models edges -| main.rs:9:13:9:19 | Param : unit | main.rs:9:30:14:1 | BlockExpr : unit | provenance | | -| main.rs:21:13:21:21 | CallExpr : unit | main.rs:22:10:22:10 | s | provenance | | -| main.rs:26:13:26:21 | CallExpr : unit | main.rs:27:22:27:22 | s : unit | provenance | | -| main.rs:27:13:27:23 | CallExpr : unit | main.rs:28:10:28:10 | s | provenance | | -| main.rs:27:22:27:22 | s : unit | main.rs:9:13:9:19 | Param : unit | provenance | | -| main.rs:27:22:27:22 | s : unit | main.rs:27:13:27:23 | CallExpr : unit | provenance | | -| main.rs:32:13:32:21 | CallExpr : unit | main.rs:33:10:33:10 | s | provenance | | +| main.rs:9:13:9:19 | Param | main.rs:9:30:14:1 | BlockExpr | provenance | | +| main.rs:21:13:21:21 | CallExpr | main.rs:22:10:22:10 | s | provenance | | +| main.rs:26:13:26:21 | CallExpr | main.rs:27:22:27:22 | s | provenance | | +| main.rs:27:13:27:23 | CallExpr | main.rs:28:10:28:10 | s | provenance | | +| main.rs:27:22:27:22 | s | main.rs:9:13:9:19 | Param | provenance | | +| main.rs:27:22:27:22 | s | main.rs:27:13:27:23 | CallExpr | provenance | | +| main.rs:32:13:32:21 | CallExpr | main.rs:33:10:33:10 | s | provenance | | nodes -| main.rs:9:13:9:19 | Param : unit | semmle.label | Param : unit | -| main.rs:9:30:14:1 | BlockExpr : unit | semmle.label | BlockExpr : unit | +| main.rs:9:13:9:19 | Param | semmle.label | Param | +| main.rs:9:30:14:1 | BlockExpr | semmle.label | BlockExpr | | main.rs:17:10:17:18 | CallExpr | semmle.label | CallExpr | -| main.rs:21:13:21:21 | CallExpr : unit | semmle.label | CallExpr : unit | +| main.rs:21:13:21:21 | CallExpr | semmle.label | CallExpr | | main.rs:22:10:22:10 | s | semmle.label | s | -| main.rs:26:13:26:21 | CallExpr : unit | semmle.label | CallExpr : unit | -| main.rs:27:13:27:23 | CallExpr : unit | semmle.label | CallExpr : unit | -| main.rs:27:22:27:22 | s : unit | semmle.label | s : unit | +| main.rs:26:13:26:21 | CallExpr | semmle.label | CallExpr | +| main.rs:27:13:27:23 | CallExpr | semmle.label | CallExpr | +| main.rs:27:22:27:22 | s | semmle.label | s | | main.rs:28:10:28:10 | s | semmle.label | s | -| main.rs:32:13:32:21 | CallExpr : unit | semmle.label | CallExpr : unit | +| main.rs:32:13:32:21 | CallExpr | semmle.label | CallExpr | | main.rs:33:10:33:10 | s | semmle.label | s | subpaths -| main.rs:27:22:27:22 | s : unit | main.rs:9:13:9:19 | Param : unit | main.rs:9:30:14:1 | BlockExpr : unit | main.rs:27:13:27:23 | CallExpr : unit | +| main.rs:27:22:27:22 | s | main.rs:9:13:9:19 | Param | main.rs:9:30:14:1 | BlockExpr | main.rs:27:13:27:23 | CallExpr | testFailures #select | main.rs:17:10:17:18 | CallExpr | main.rs:17:10:17:18 | CallExpr | main.rs:17:10:17:18 | CallExpr | $@ | main.rs:17:10:17:18 | CallExpr | CallExpr | -| main.rs:22:10:22:10 | s | main.rs:21:13:21:21 | CallExpr : unit | main.rs:22:10:22:10 | s | $@ | main.rs:21:13:21:21 | CallExpr : unit | CallExpr : unit | -| main.rs:28:10:28:10 | s | main.rs:26:13:26:21 | CallExpr : unit | main.rs:28:10:28:10 | s | $@ | main.rs:26:13:26:21 | CallExpr : unit | CallExpr : unit | -| main.rs:33:10:33:10 | s | main.rs:32:13:32:21 | CallExpr : unit | main.rs:33:10:33:10 | s | $@ | main.rs:32:13:32:21 | CallExpr : unit | CallExpr : unit | +| main.rs:22:10:22:10 | s | main.rs:21:13:21:21 | CallExpr | main.rs:22:10:22:10 | s | $@ | main.rs:21:13:21:21 | CallExpr | CallExpr | +| main.rs:28:10:28:10 | s | main.rs:26:13:26:21 | CallExpr | main.rs:28:10:28:10 | s | $@ | main.rs:26:13:26:21 | CallExpr | CallExpr | +| main.rs:33:10:33:10 | s | main.rs:32:13:32:21 | CallExpr | main.rs:33:10:33:10 | s | $@ | main.rs:32:13:32:21 | CallExpr | CallExpr | diff --git a/rust/ql/test/library-tests/dataflow/global/inline-flow.expected b/rust/ql/test/library-tests/dataflow/global/inline-flow.expected index 8c1d90ee45a6..0c2412d6ff6a 100644 --- a/rust/ql/test/library-tests/dataflow/global/inline-flow.expected +++ b/rust/ql/test/library-tests/dataflow/global/inline-flow.expected @@ -1,74 +1,74 @@ models edges -| main.rs:12:28:14:1 | BlockExpr : unit | main.rs:17:13:17:23 | CallExpr : unit | provenance | | -| main.rs:13:5:13:13 | CallExpr : unit | main.rs:12:28:14:1 | BlockExpr : unit | provenance | | -| main.rs:17:13:17:23 | CallExpr : unit | main.rs:18:10:18:10 | a | provenance | | -| main.rs:21:12:21:17 | Param : unit | main.rs:22:10:22:10 | n | provenance | | -| main.rs:26:13:26:21 | CallExpr : unit | main.rs:27:13:27:13 | a : unit | provenance | | -| main.rs:27:13:27:13 | a : unit | main.rs:21:12:21:17 | Param : unit | provenance | | -| main.rs:30:17:30:22 | Param : unit | main.rs:30:32:32:1 | BlockExpr : unit | provenance | | -| main.rs:35:13:35:21 | CallExpr : unit | main.rs:36:26:36:26 | a : unit | provenance | | -| main.rs:36:13:36:27 | CallExpr : unit | main.rs:37:10:37:10 | b | provenance | | -| main.rs:36:26:36:26 | a : unit | main.rs:30:17:30:22 | Param : unit | provenance | | -| main.rs:36:26:36:26 | a : unit | main.rs:36:13:36:27 | CallExpr : unit | provenance | | -| main.rs:41:13:44:6 | CallExpr : unit | main.rs:45:10:45:10 | a | provenance | | -| main.rs:41:26:44:5 | BlockExpr : unit | main.rs:30:17:30:22 | Param : unit | provenance | | -| main.rs:41:26:44:5 | BlockExpr : unit | main.rs:41:13:44:6 | CallExpr : unit | provenance | | -| main.rs:43:9:43:18 | CallExpr : unit | main.rs:41:26:44:5 | BlockExpr : unit | provenance | | -| main.rs:56:23:56:28 | Param : unit | main.rs:57:14:57:14 | n | provenance | | -| main.rs:59:31:65:5 | BlockExpr : unit | main.rs:77:13:77:25 | ... .get_data(...) : unit | provenance | | -| main.rs:63:13:63:21 | CallExpr : unit | main.rs:59:31:65:5 | BlockExpr : unit | provenance | | -| main.rs:66:28:66:33 | Param : unit | main.rs:66:43:72:5 | BlockExpr : unit | provenance | | -| main.rs:77:13:77:25 | ... .get_data(...) : unit | main.rs:78:10:78:10 | a | provenance | | -| main.rs:83:13:83:21 | CallExpr : unit | main.rs:84:16:84:16 | a : unit | provenance | | -| main.rs:84:16:84:16 | a : unit | main.rs:56:23:56:28 | Param : unit | provenance | | -| main.rs:89:13:89:21 | CallExpr : unit | main.rs:90:29:90:29 | a : unit | provenance | | -| main.rs:90:13:90:30 | ... .data_through(...) : unit | main.rs:91:10:91:10 | b | provenance | | -| main.rs:90:29:90:29 | a : unit | main.rs:66:28:66:33 | Param : unit | provenance | | -| main.rs:90:29:90:29 | a : unit | main.rs:90:13:90:30 | ... .data_through(...) : unit | provenance | | +| main.rs:12:28:14:1 | BlockExpr | main.rs:17:13:17:23 | CallExpr | provenance | | +| main.rs:13:5:13:13 | CallExpr | main.rs:12:28:14:1 | BlockExpr | provenance | | +| main.rs:17:13:17:23 | CallExpr | main.rs:18:10:18:10 | a | provenance | | +| main.rs:21:12:21:17 | Param | main.rs:22:10:22:10 | n | provenance | | +| main.rs:26:13:26:21 | CallExpr | main.rs:27:13:27:13 | a | provenance | | +| main.rs:27:13:27:13 | a | main.rs:21:12:21:17 | Param | provenance | | +| main.rs:30:17:30:22 | Param | main.rs:30:32:32:1 | BlockExpr | provenance | | +| main.rs:35:13:35:21 | CallExpr | main.rs:36:26:36:26 | a | provenance | | +| main.rs:36:13:36:27 | CallExpr | main.rs:37:10:37:10 | b | provenance | | +| main.rs:36:26:36:26 | a | main.rs:30:17:30:22 | Param | provenance | | +| main.rs:36:26:36:26 | a | main.rs:36:13:36:27 | CallExpr | provenance | | +| main.rs:41:13:44:6 | CallExpr | main.rs:45:10:45:10 | a | provenance | | +| main.rs:41:26:44:5 | BlockExpr | main.rs:30:17:30:22 | Param | provenance | | +| main.rs:41:26:44:5 | BlockExpr | main.rs:41:13:44:6 | CallExpr | provenance | | +| main.rs:43:9:43:18 | CallExpr | main.rs:41:26:44:5 | BlockExpr | provenance | | +| main.rs:56:23:56:28 | Param | main.rs:57:14:57:14 | n | provenance | | +| main.rs:59:31:65:5 | BlockExpr | main.rs:77:13:77:25 | ... .get_data(...) | provenance | | +| main.rs:63:13:63:21 | CallExpr | main.rs:59:31:65:5 | BlockExpr | provenance | | +| main.rs:66:28:66:33 | Param | main.rs:66:43:72:5 | BlockExpr | provenance | | +| main.rs:77:13:77:25 | ... .get_data(...) | main.rs:78:10:78:10 | a | provenance | | +| main.rs:83:13:83:21 | CallExpr | main.rs:84:16:84:16 | a | provenance | | +| main.rs:84:16:84:16 | a | main.rs:56:23:56:28 | Param | provenance | | +| main.rs:89:13:89:21 | CallExpr | main.rs:90:29:90:29 | a | provenance | | +| main.rs:90:13:90:30 | ... .data_through(...) | main.rs:91:10:91:10 | b | provenance | | +| main.rs:90:29:90:29 | a | main.rs:66:28:66:33 | Param | provenance | | +| main.rs:90:29:90:29 | a | main.rs:90:13:90:30 | ... .data_through(...) | provenance | | nodes -| main.rs:12:28:14:1 | BlockExpr : unit | semmle.label | BlockExpr : unit | -| main.rs:13:5:13:13 | CallExpr : unit | semmle.label | CallExpr : unit | -| main.rs:17:13:17:23 | CallExpr : unit | semmle.label | CallExpr : unit | +| main.rs:12:28:14:1 | BlockExpr | semmle.label | BlockExpr | +| main.rs:13:5:13:13 | CallExpr | semmle.label | CallExpr | +| main.rs:17:13:17:23 | CallExpr | semmle.label | CallExpr | | main.rs:18:10:18:10 | a | semmle.label | a | -| main.rs:21:12:21:17 | Param : unit | semmle.label | Param : unit | +| main.rs:21:12:21:17 | Param | semmle.label | Param | | main.rs:22:10:22:10 | n | semmle.label | n | -| main.rs:26:13:26:21 | CallExpr : unit | semmle.label | CallExpr : unit | -| main.rs:27:13:27:13 | a : unit | semmle.label | a : unit | -| main.rs:30:17:30:22 | Param : unit | semmle.label | Param : unit | -| main.rs:30:32:32:1 | BlockExpr : unit | semmle.label | BlockExpr : unit | -| main.rs:35:13:35:21 | CallExpr : unit | semmle.label | CallExpr : unit | -| main.rs:36:13:36:27 | CallExpr : unit | semmle.label | CallExpr : unit | -| main.rs:36:26:36:26 | a : unit | semmle.label | a : unit | +| main.rs:26:13:26:21 | CallExpr | semmle.label | CallExpr | +| main.rs:27:13:27:13 | a | semmle.label | a | +| main.rs:30:17:30:22 | Param | semmle.label | Param | +| main.rs:30:32:32:1 | BlockExpr | semmle.label | BlockExpr | +| main.rs:35:13:35:21 | CallExpr | semmle.label | CallExpr | +| main.rs:36:13:36:27 | CallExpr | semmle.label | CallExpr | +| main.rs:36:26:36:26 | a | semmle.label | a | | main.rs:37:10:37:10 | b | semmle.label | b | -| main.rs:41:13:44:6 | CallExpr : unit | semmle.label | CallExpr : unit | -| main.rs:41:26:44:5 | BlockExpr : unit | semmle.label | BlockExpr : unit | -| main.rs:43:9:43:18 | CallExpr : unit | semmle.label | CallExpr : unit | +| main.rs:41:13:44:6 | CallExpr | semmle.label | CallExpr | +| main.rs:41:26:44:5 | BlockExpr | semmle.label | BlockExpr | +| main.rs:43:9:43:18 | CallExpr | semmle.label | CallExpr | | main.rs:45:10:45:10 | a | semmle.label | a | -| main.rs:56:23:56:28 | Param : unit | semmle.label | Param : unit | +| main.rs:56:23:56:28 | Param | semmle.label | Param | | main.rs:57:14:57:14 | n | semmle.label | n | -| main.rs:59:31:65:5 | BlockExpr : unit | semmle.label | BlockExpr : unit | -| main.rs:63:13:63:21 | CallExpr : unit | semmle.label | CallExpr : unit | -| main.rs:66:28:66:33 | Param : unit | semmle.label | Param : unit | -| main.rs:66:43:72:5 | BlockExpr : unit | semmle.label | BlockExpr : unit | -| main.rs:77:13:77:25 | ... .get_data(...) : unit | semmle.label | ... .get_data(...) : unit | +| main.rs:59:31:65:5 | BlockExpr | semmle.label | BlockExpr | +| main.rs:63:13:63:21 | CallExpr | semmle.label | CallExpr | +| main.rs:66:28:66:33 | Param | semmle.label | Param | +| main.rs:66:43:72:5 | BlockExpr | semmle.label | BlockExpr | +| main.rs:77:13:77:25 | ... .get_data(...) | semmle.label | ... .get_data(...) | | main.rs:78:10:78:10 | a | semmle.label | a | -| main.rs:83:13:83:21 | CallExpr : unit | semmle.label | CallExpr : unit | -| main.rs:84:16:84:16 | a : unit | semmle.label | a : unit | -| main.rs:89:13:89:21 | CallExpr : unit | semmle.label | CallExpr : unit | -| main.rs:90:13:90:30 | ... .data_through(...) : unit | semmle.label | ... .data_through(...) : unit | -| main.rs:90:29:90:29 | a : unit | semmle.label | a : unit | +| main.rs:83:13:83:21 | CallExpr | semmle.label | CallExpr | +| main.rs:84:16:84:16 | a | semmle.label | a | +| main.rs:89:13:89:21 | CallExpr | semmle.label | CallExpr | +| main.rs:90:13:90:30 | ... .data_through(...) | semmle.label | ... .data_through(...) | +| main.rs:90:29:90:29 | a | semmle.label | a | | main.rs:91:10:91:10 | b | semmle.label | b | subpaths -| main.rs:36:26:36:26 | a : unit | main.rs:30:17:30:22 | Param : unit | main.rs:30:32:32:1 | BlockExpr : unit | main.rs:36:13:36:27 | CallExpr : unit | -| main.rs:41:26:44:5 | BlockExpr : unit | main.rs:30:17:30:22 | Param : unit | main.rs:30:32:32:1 | BlockExpr : unit | main.rs:41:13:44:6 | CallExpr : unit | -| main.rs:90:29:90:29 | a : unit | main.rs:66:28:66:33 | Param : unit | main.rs:66:43:72:5 | BlockExpr : unit | main.rs:90:13:90:30 | ... .data_through(...) : unit | +| main.rs:36:26:36:26 | a | main.rs:30:17:30:22 | Param | main.rs:30:32:32:1 | BlockExpr | main.rs:36:13:36:27 | CallExpr | +| main.rs:41:26:44:5 | BlockExpr | main.rs:30:17:30:22 | Param | main.rs:30:32:32:1 | BlockExpr | main.rs:41:13:44:6 | CallExpr | +| main.rs:90:29:90:29 | a | main.rs:66:28:66:33 | Param | main.rs:66:43:72:5 | BlockExpr | main.rs:90:13:90:30 | ... .data_through(...) | testFailures #select -| main.rs:18:10:18:10 | a | main.rs:13:5:13:13 | CallExpr : unit | main.rs:18:10:18:10 | a | $@ | main.rs:13:5:13:13 | CallExpr : unit | CallExpr : unit | -| main.rs:22:10:22:10 | n | main.rs:26:13:26:21 | CallExpr : unit | main.rs:22:10:22:10 | n | $@ | main.rs:26:13:26:21 | CallExpr : unit | CallExpr : unit | -| main.rs:37:10:37:10 | b | main.rs:35:13:35:21 | CallExpr : unit | main.rs:37:10:37:10 | b | $@ | main.rs:35:13:35:21 | CallExpr : unit | CallExpr : unit | -| main.rs:45:10:45:10 | a | main.rs:43:9:43:18 | CallExpr : unit | main.rs:45:10:45:10 | a | $@ | main.rs:43:9:43:18 | CallExpr : unit | CallExpr : unit | -| main.rs:57:14:57:14 | n | main.rs:83:13:83:21 | CallExpr : unit | main.rs:57:14:57:14 | n | $@ | main.rs:83:13:83:21 | CallExpr : unit | CallExpr : unit | -| main.rs:78:10:78:10 | a | main.rs:63:13:63:21 | CallExpr : unit | main.rs:78:10:78:10 | a | $@ | main.rs:63:13:63:21 | CallExpr : unit | CallExpr : unit | -| main.rs:91:10:91:10 | b | main.rs:89:13:89:21 | CallExpr : unit | main.rs:91:10:91:10 | b | $@ | main.rs:89:13:89:21 | CallExpr : unit | CallExpr : unit | +| main.rs:18:10:18:10 | a | main.rs:13:5:13:13 | CallExpr | main.rs:18:10:18:10 | a | $@ | main.rs:13:5:13:13 | CallExpr | CallExpr | +| main.rs:22:10:22:10 | n | main.rs:26:13:26:21 | CallExpr | main.rs:22:10:22:10 | n | $@ | main.rs:26:13:26:21 | CallExpr | CallExpr | +| main.rs:37:10:37:10 | b | main.rs:35:13:35:21 | CallExpr | main.rs:37:10:37:10 | b | $@ | main.rs:35:13:35:21 | CallExpr | CallExpr | +| main.rs:45:10:45:10 | a | main.rs:43:9:43:18 | CallExpr | main.rs:45:10:45:10 | a | $@ | main.rs:43:9:43:18 | CallExpr | CallExpr | +| main.rs:57:14:57:14 | n | main.rs:83:13:83:21 | CallExpr | main.rs:57:14:57:14 | n | $@ | main.rs:83:13:83:21 | CallExpr | CallExpr | +| main.rs:78:10:78:10 | a | main.rs:63:13:63:21 | CallExpr | main.rs:78:10:78:10 | a | $@ | main.rs:63:13:63:21 | CallExpr | CallExpr | +| main.rs:91:10:91:10 | b | main.rs:89:13:89:21 | CallExpr | main.rs:91:10:91:10 | b | $@ | main.rs:89:13:89:21 | CallExpr | CallExpr | diff --git a/rust/ql/test/library-tests/dataflow/local/inline-flow.expected b/rust/ql/test/library-tests/dataflow/local/inline-flow.expected index 3cb35a1079fe..98289b67da64 100644 --- a/rust/ql/test/library-tests/dataflow/local/inline-flow.expected +++ b/rust/ql/test/library-tests/dataflow/local/inline-flow.expected @@ -1,28 +1,28 @@ models edges -| main.rs:19:13:19:21 | CallExpr : unit | main.rs:20:10:20:10 | s | provenance | | -| main.rs:24:13:24:21 | CallExpr : unit | main.rs:27:10:27:10 | c | provenance | | -| main.rs:31:13:31:21 | CallExpr : unit | main.rs:36:10:36:10 | b | provenance | | -| main.rs:45:15:45:23 | CallExpr : unit | main.rs:47:10:47:10 | b | provenance | | -| main.rs:53:9:53:17 | CallExpr : unit | main.rs:54:10:54:10 | i | provenance | | +| main.rs:19:13:19:21 | CallExpr | main.rs:20:10:20:10 | s | provenance | | +| main.rs:24:13:24:21 | CallExpr | main.rs:27:10:27:10 | c | provenance | | +| main.rs:31:13:31:21 | CallExpr | main.rs:36:10:36:10 | b | provenance | | +| main.rs:45:15:45:23 | CallExpr | main.rs:47:10:47:10 | b | provenance | | +| main.rs:53:9:53:17 | CallExpr | main.rs:54:10:54:10 | i | provenance | | nodes | main.rs:15:10:15:18 | CallExpr | semmle.label | CallExpr | -| main.rs:19:13:19:21 | CallExpr : unit | semmle.label | CallExpr : unit | +| main.rs:19:13:19:21 | CallExpr | semmle.label | CallExpr | | main.rs:20:10:20:10 | s | semmle.label | s | -| main.rs:24:13:24:21 | CallExpr : unit | semmle.label | CallExpr : unit | +| main.rs:24:13:24:21 | CallExpr | semmle.label | CallExpr | | main.rs:27:10:27:10 | c | semmle.label | c | -| main.rs:31:13:31:21 | CallExpr : unit | semmle.label | CallExpr : unit | +| main.rs:31:13:31:21 | CallExpr | semmle.label | CallExpr | | main.rs:36:10:36:10 | b | semmle.label | b | -| main.rs:45:15:45:23 | CallExpr : unit | semmle.label | CallExpr : unit | +| main.rs:45:15:45:23 | CallExpr | semmle.label | CallExpr | | main.rs:47:10:47:10 | b | semmle.label | b | -| main.rs:53:9:53:17 | CallExpr : unit | semmle.label | CallExpr : unit | +| main.rs:53:9:53:17 | CallExpr | semmle.label | CallExpr | | main.rs:54:10:54:10 | i | semmle.label | i | subpaths testFailures #select | main.rs:15:10:15:18 | CallExpr | main.rs:15:10:15:18 | CallExpr | main.rs:15:10:15:18 | CallExpr | $@ | main.rs:15:10:15:18 | CallExpr | CallExpr | -| main.rs:20:10:20:10 | s | main.rs:19:13:19:21 | CallExpr : unit | main.rs:20:10:20:10 | s | $@ | main.rs:19:13:19:21 | CallExpr : unit | CallExpr : unit | -| main.rs:27:10:27:10 | c | main.rs:24:13:24:21 | CallExpr : unit | main.rs:27:10:27:10 | c | $@ | main.rs:24:13:24:21 | CallExpr : unit | CallExpr : unit | -| main.rs:36:10:36:10 | b | main.rs:31:13:31:21 | CallExpr : unit | main.rs:36:10:36:10 | b | $@ | main.rs:31:13:31:21 | CallExpr : unit | CallExpr : unit | -| main.rs:47:10:47:10 | b | main.rs:45:15:45:23 | CallExpr : unit | main.rs:47:10:47:10 | b | $@ | main.rs:45:15:45:23 | CallExpr : unit | CallExpr : unit | -| main.rs:54:10:54:10 | i | main.rs:53:9:53:17 | CallExpr : unit | main.rs:54:10:54:10 | i | $@ | main.rs:53:9:53:17 | CallExpr : unit | CallExpr : unit | +| main.rs:20:10:20:10 | s | main.rs:19:13:19:21 | CallExpr | main.rs:20:10:20:10 | s | $@ | main.rs:19:13:19:21 | CallExpr | CallExpr | +| main.rs:27:10:27:10 | c | main.rs:24:13:24:21 | CallExpr | main.rs:27:10:27:10 | c | $@ | main.rs:24:13:24:21 | CallExpr | CallExpr | +| main.rs:36:10:36:10 | b | main.rs:31:13:31:21 | CallExpr | main.rs:36:10:36:10 | b | $@ | main.rs:31:13:31:21 | CallExpr | CallExpr | +| main.rs:47:10:47:10 | b | main.rs:45:15:45:23 | CallExpr | main.rs:47:10:47:10 | b | $@ | main.rs:45:15:45:23 | CallExpr | CallExpr | +| main.rs:54:10:54:10 | i | main.rs:53:9:53:17 | CallExpr | main.rs:54:10:54:10 | i | $@ | main.rs:53:9:53:17 | CallExpr | CallExpr | From 02c27ddc3d234ce078919ccea23c50ba07816e1d Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 22 Nov 2024 14:54:39 +0100 Subject: [PATCH 4/4] Rust: Flow through enum constructors --- rust/ql/lib/codeql/rust/dataflow/DataFlow.qll | 4 + .../rust/dataflow/internal/DataFlowImpl.qll | 254 ++++++++++++------ .../dataflow/local/DataFlowStep.expected | 18 ++ .../dataflow/local/inline-flow.expected | 20 ++ .../test/library-tests/dataflow/local/main.rs | 4 +- 5 files changed, 222 insertions(+), 78 deletions(-) diff --git a/rust/ql/lib/codeql/rust/dataflow/DataFlow.qll b/rust/ql/lib/codeql/rust/dataflow/DataFlow.qll index 3a09df2c45d1..2b00342ef6ef 100644 --- a/rust/ql/lib/codeql/rust/dataflow/DataFlow.qll +++ b/rust/ql/lib/codeql/rust/dataflow/DataFlow.qll @@ -19,6 +19,10 @@ module DataFlow { final class PostUpdateNode = Node::PostUpdateNode; + final class Content = DataFlowImpl::Content; + + final class ContentSet = DataFlowImpl::ContentSet; + /** * Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local * (intra-procedural) step. diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll index 4e892e8d19c7..fb77e62a3534 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll @@ -115,6 +115,11 @@ module Node { */ ExprCfgNode asExpr() { none() } + /** + * Gets the pattern that corresponds to this node, if any. + */ + PatCfgNode asPat() { none() } + /** Gets the enclosing callable. */ DataFlowCallable getEnclosingCallable() { result = TCfgScope(this.getCfgScope()) } @@ -177,8 +182,7 @@ module Node { PatNode() { this = TPatNode(n) } - /** Gets the `PatCfgNode` in the CFG that this node corresponds to. */ - PatCfgNode getPat() { result = n } + override PatCfgNode asPat() { result = n } } abstract class ParameterNode extends AstCfgFlowNode { } @@ -333,8 +337,7 @@ module LocalFlow { nodeFrom.(Node::AstCfgFlowNode).getCfgNode() = nodeTo.(Node::SsaNode).getDefinitionExt().(Ssa::WriteDefinition).getControlFlowNode() or - nodeFrom.(Node::PositionalParameterNode).getParameter().getPat() = - nodeTo.(Node::PatNode).getPat() + nodeFrom.(Node::PositionalParameterNode).getParameter().getPat() = nodeTo.asPat() or SsaFlow::localFlowStep(_, nodeFrom, nodeTo, _) or @@ -342,9 +345,129 @@ module LocalFlow { a.getRhs() = nodeFrom.getCfgNode() and a.getLhs() = nodeTo.getCfgNode() ) + or + exists(MatchExprCfgNode match | + nodeFrom.asExpr() = match.getExpr() and + nodeTo.asPat() = match.getArmPat(_) + ) } } +abstract class Content extends TContent { + abstract string toString(); +} + +abstract private class VariantContent extends Content { + string name; + + bindingset[this, name] + VariantContent() { exists(name) } +} + +private class VariantTupleContent extends VariantContent, TVariantTupleContent { + private CrateOriginOption crate; + private string path; + private int i; + + VariantTupleContent() { this = TVariantTupleContent(crate, path, name, i) } + + final override string toString() { + if exists(TVariantTupleContent(crate, path, name, 1)) + then result = name + "(" + i + ")" + else result = name + } +} + +abstract class ContentSet extends TContentSet { + /** Gets a textual representation of this element. */ + abstract string toString(); + + /** Gets a content that may be stored into when storing into this set. */ + abstract Content getAStoreContent(); + + /** Gets a content that may be read from when reading from this set. */ + abstract Content getAReadContent(); +} + +private class SingletonContentSet extends ContentSet, TSingletonContentSet { + private Content c; + + SingletonContentSet() { this = TSingletonContentSet(c) } + + Content getContent() { result = c } + + override string toString() { result = c.toString() } + + override Content getAStoreContent() { result = c } + + override Content getAReadContent() { result = c } +} + +private import codeql.util.Option + +private class CrateOrigin extends string { + CrateOrigin() { + this = [any(Item i).getCrateOrigin(), any(Resolvable r).getResolvedCrateOrigin()] + } +} + +private class CrateOriginOption = Option::Option; + +pragma[nomagic] +private predicate hasExtendedCanonicalPath(Item i, CrateOriginOption crate, string path) { + path = i.getExtendedCanonicalPath() and + ( + crate.asSome() = i.getCrateOrigin() + or + crate.isNone() and + not i.hasCrateOrigin() + ) +} + +pragma[nomagic] +private predicate resolvesExtendedCanonicalPath(Resolvable r, CrateOriginOption crate, string path) { + path = r.getResolvedPath() and + ( + crate.asSome() = r.getResolvedCrateOrigin() + or + crate.isNone() and + not r.hasResolvedCrateOrigin() + ) +} + +pragma[nomagic] +private predicate callResolvesExtendedCanonicalPath( + CallExprBase call, CrateOriginOption crate, string path +) { + exists(Resolvable r | resolvesExtendedCanonicalPath(r, crate, path) | + r = call.(MethodCallExpr) + or + r = call.(CallExpr).getExpr().(PathExpr).getPath() + ) +} + +/** Holds if qualified path `p` resolves to variant `c`. */ +private predicate pathResolvesToVariant(Path p, VariantContent c, int i) { + exists(CrateOriginOption crate, string path | + resolvesExtendedCanonicalPath(p.getQualifier(), crate, path) and + c = TVariantTupleContent(crate, path, p.getPart().getNameRef().getText(), i) + ) + or + // TODO: Remove once library types are extracted + not p.hasQualifier() and + c = TVariantTupleContent(_, "crate::std::option::Option", p.getPart().getNameRef().getText(), i) +} + +/** Holds if `ce` constructs an enum value of type `c`. */ +private predicate variantConstructor(CallExpr ce, VariantContent c, int i) { + pathResolvesToVariant(ce.getExpr().(PathExpr).getPath(), c, i) +} + +/** Holds if `p` destructs an enum value of type `c`. */ +private predicate variantDestructor(TupleStructPat p, VariantContent c, int i) { + pathResolvesToVariant(p.getPath(), c, i) +} + private class DataFlowCallableAlias = DataFlowCallable; private class ReturnKindAlias = ReturnKind; @@ -353,6 +476,10 @@ private class DataFlowCallAlias = DataFlowCall; private class ParameterPositionAlias = ParameterPosition; +private class ContentAlias = Content; + +private class ContentSetAlias = ContentSet; + module RustDataFlow implements InputSig { /** * An element, viewed as a node in a data flow graph. Either an expression @@ -399,55 +526,11 @@ module RustDataFlow implements InputSig { final class ReturnKind = ReturnKindAlias; - private import codeql.util.Option - - private class CrateOrigin extends string { - CrateOrigin() { - this = [any(Item i).getCrateOrigin(), any(Resolvable r).getResolvedCrateOrigin()] - } - } - - private class CrateOriginOption = Option::Option; - - pragma[nomagic] - private predicate hasExtendedCanonicalPath( - DataFlowCallable c, CrateOriginOption crate, string path - ) { - exists(Item i | - i = c.asCfgScope() and - path = i.getExtendedCanonicalPath() - | - crate.asSome() = i.getCrateOrigin() - or - crate.isNone() and - not i.hasCrateOrigin() - ) - } - - pragma[nomagic] - private predicate resolvesExtendedCanonicalPath( - DataFlowCall c, CrateOriginOption crate, string path - ) { - exists(Resolvable r | - path = r.getResolvedPath() and - ( - r = c.asMethodCallExprCfgNode().getExpr() - or - r = c.asCallExprCfgNode().getExpr().(PathExprCfgNode).getPath() - ) - | - crate.asSome() = r.getResolvedCrateOrigin() - or - crate.isNone() and - not r.hasResolvedCrateOrigin() - ) - } - /** Gets a viable implementation of the target of the given `Call`. */ DataFlowCallable viableCallable(DataFlowCall call) { exists(string path, CrateOriginOption crate | - hasExtendedCanonicalPath(result, crate, path) and - resolvesExtendedCanonicalPath(call, crate, path) + hasExtendedCanonicalPath(result.asCfgScope(), crate, path) and + callResolvesExtendedCanonicalPath(call.asCallBaseExprCfgNode().getExpr(), crate, path) ) } @@ -469,24 +552,15 @@ module RustDataFlow implements InputSig { predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() } - final class Content = Void; + class Content = ContentAlias; - predicate forceHighPrecision(Content c) { none() } - - class ContentSet extends TContentSet { - /** Gets a textual representation of this element. */ - string toString() { result = "ContentSet" } - - /** Gets a content that may be stored into when storing into this set. */ - Content getAStoreContent() { none() } + class ContentSet = ContentSetAlias; - /** Gets a content that may be read from when reading from this set. */ - Content getAReadContent() { none() } - } + predicate forceHighPrecision(Content c) { none() } - final class ContentApprox = Void; + final class ContentApprox = Content; // todo - ContentApprox getContentApprox(Content c) { any() } + ContentApprox getContentApprox(Content c) { result = c } class ParameterPosition = ParameterPositionAlias; @@ -519,14 +593,31 @@ module RustDataFlow implements InputSig { * `node1` references an object with a content `c.getAReadContent()` whose * value ends up in `node2`. */ - predicate readStep(Node node1, ContentSet c, Node node2) { none() } + predicate readStep(Node node1, ContentSet c, Node node2) { + node1.asPat() = + any(TupleStructPatCfgNode pat, int i | + variantDestructor(pat.getPat(), c.(SingletonContentSet).getContent(), i) and + node2.asPat() = pat.getField(i) + | + pat + ) + } /** * Holds if data can flow from `node1` to `node2` via a store into `c`. Thus, * `node2` references an object with a content `c.getAStoreContent()` that * contains the value of `node1`. */ - predicate storeStep(Node node1, ContentSet c, Node node2) { none() } + predicate storeStep(Node node1, ContentSet c, Node node2) { + // todo: use post-update + node2.asExpr() = + any(CallExprCfgNode call, int i | + variantConstructor(call.getCallExpr(), c.(SingletonContentSet).getContent(), i) and + node1.asExpr() = call.getArgument(i) + | + call + ) + } /** * Holds if values stored inside content `c` are cleared at node `n`. For example, @@ -593,8 +684,6 @@ module RustDataFlow implements InputSig { class DataFlowSecondLevelScope = Void; } -final class ContentSet = RustDataFlow::ContentSet; - import MakeImpl /** A collection of cached types and predicates to be evaluated in the same stage. */ @@ -612,14 +701,6 @@ private module Cached { cached newtype TDataFlowCall = TCall(CallExprBaseCfgNode c) - cached - newtype TOptionalContentSet = - TAnyElementContent() or - TAnyContent() - - cached - class TContentSet = TAnyElementContent or TAnyContent; - cached newtype TDataFlowCallable = TCfgScope(CfgScope scope) @@ -635,6 +716,27 @@ private module Cached { i in [0 .. max([any(ParamList l).getNumberOfParams(), any(ArgList l).getNumberOfArgs()]) - 1] } or TSelfParameterPosition() + + cached + newtype TContent = + TVariantTupleContent(CrateOriginOption crate, string path, string name, int i) { + exists(Enum e, Variant v | + hasExtendedCanonicalPath(e, crate, path) and + v = e.getVariantList().getAVariant() and + name = v.getName().getText() and + i in [0 .. v.getFieldList().(TupleFieldList).getNumberOfFields() - 1] + ) + or + // TODO: Remove once library types are extracted + crate.isNone() and + path = "crate::std::option::Option" and + name = "Some" and + i = 0 + } + + // todo: add TVariantRecordContent + cached + newtype TContentSet = TSingletonContentSet(Content c) } import Cached diff --git a/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected b/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected index 433f38706457..dd5926064bb9 100644 --- a/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -33,6 +33,8 @@ | main.rs:32:9:32:9 | [SSA] b | main.rs:36:10:36:10 | b | | main.rs:32:9:32:9 | b | main.rs:32:9:32:9 | [SSA] b | | main.rs:32:13:35:5 | MatchExpr | main.rs:32:9:32:9 | b | +| main.rs:32:19:32:19 | m | main.rs:33:9:33:15 | TupleStructPat | +| main.rs:32:19:32:19 | m | main.rs:34:9:34:12 | None | | main.rs:33:20:33:20 | a | main.rs:32:13:35:5 | MatchExpr | | main.rs:34:17:34:17 | 0 | main.rs:32:13:35:5 | MatchExpr | | main.rs:40:9:40:9 | [SSA] a | main.rs:43:10:43:10 | a | @@ -79,11 +81,15 @@ | main.rs:105:9:105:10 | [SSA] s2 | main.rs:110:11:110:12 | s2 | | main.rs:105:9:105:10 | s2 | main.rs:105:9:105:10 | [SSA] s2 | | main.rs:105:14:105:28 | CallExpr | main.rs:105:9:105:10 | s2 | +| main.rs:106:11:106:12 | s1 | main.rs:107:9:107:23 | TupleStructPat | +| main.rs:106:11:106:12 | s1 | main.rs:108:9:108:20 | PathPat | | main.rs:107:22:107:22 | [SSA] n | main.rs:107:33:107:33 | n | | main.rs:107:22:107:22 | n | main.rs:107:22:107:22 | [SSA] n | | main.rs:107:28:107:34 | CallExpr | main.rs:106:5:109:5 | MatchExpr | | main.rs:108:25:108:31 | CallExpr | main.rs:106:5:109:5 | MatchExpr | | main.rs:110:5:113:5 | MatchExpr | main.rs:103:37:114:1 | BlockExpr | +| main.rs:110:11:110:12 | s2 | main.rs:111:9:111:23 | TupleStructPat | +| main.rs:110:11:110:12 | s2 | main.rs:112:9:112:20 | PathPat | | main.rs:111:22:111:22 | [SSA] n | main.rs:111:33:111:33 | n | | main.rs:111:22:111:22 | n | main.rs:111:22:111:22 | [SSA] n | | main.rs:111:28:111:34 | CallExpr | main.rs:110:5:113:5 | MatchExpr | @@ -94,11 +100,15 @@ | main.rs:118:9:118:10 | [SSA] s2 | main.rs:123:11:123:12 | s2 | | main.rs:118:9:118:10 | s2 | main.rs:118:9:118:10 | [SSA] s2 | | main.rs:118:14:118:20 | CallExpr | main.rs:118:9:118:10 | s2 | +| main.rs:119:11:119:12 | s1 | main.rs:120:9:120:15 | TupleStructPat | +| main.rs:119:11:119:12 | s1 | main.rs:121:9:121:12 | None | | main.rs:120:14:120:14 | [SSA] n | main.rs:120:25:120:25 | n | | main.rs:120:14:120:14 | n | main.rs:120:14:120:14 | [SSA] n | | main.rs:120:20:120:26 | CallExpr | main.rs:119:5:122:5 | MatchExpr | | main.rs:121:17:121:23 | CallExpr | main.rs:119:5:122:5 | MatchExpr | | main.rs:123:5:126:5 | MatchExpr | main.rs:116:39:127:1 | BlockExpr | +| main.rs:123:11:123:12 | s2 | main.rs:124:9:124:15 | TupleStructPat | +| main.rs:123:11:123:12 | s2 | main.rs:125:9:125:12 | None | | main.rs:124:14:124:14 | [SSA] n | main.rs:124:25:124:25 | n | | main.rs:124:14:124:14 | n | main.rs:124:14:124:14 | [SSA] n | | main.rs:124:20:124:26 | CallExpr | main.rs:123:5:126:5 | MatchExpr | @@ -109,6 +119,8 @@ | main.rs:136:9:136:10 | [SSA] s2 | main.rs:141:11:141:12 | s2 | | main.rs:136:9:136:10 | s2 | main.rs:136:9:136:10 | [SSA] s2 | | main.rs:136:14:136:25 | CallExpr | main.rs:136:9:136:10 | s2 | +| main.rs:137:11:137:12 | s1 | main.rs:138:9:138:20 | TupleStructPat | +| main.rs:137:11:137:12 | s1 | main.rs:139:9:139:20 | TupleStructPat | | main.rs:138:19:138:19 | [SSA] n | main.rs:138:30:138:30 | n | | main.rs:138:19:138:19 | n | main.rs:138:19:138:19 | [SSA] n | | main.rs:138:25:138:31 | CallExpr | main.rs:137:5:140:5 | MatchExpr | @@ -116,6 +128,8 @@ | main.rs:139:19:139:19 | n | main.rs:139:19:139:19 | [SSA] n | | main.rs:139:25:139:31 | CallExpr | main.rs:137:5:140:5 | MatchExpr | | main.rs:141:5:144:5 | MatchExpr | main.rs:134:42:145:1 | BlockExpr | +| main.rs:141:11:141:12 | s2 | main.rs:142:9:142:20 | TupleStructPat | +| main.rs:141:11:141:12 | s2 | main.rs:143:9:143:20 | TupleStructPat | | main.rs:142:19:142:19 | [SSA] n | main.rs:142:30:142:30 | n | | main.rs:142:19:142:19 | n | main.rs:142:19:142:19 | [SSA] n | | main.rs:142:25:142:31 | CallExpr | main.rs:141:5:144:5 | MatchExpr | @@ -128,6 +142,8 @@ | main.rs:151:9:151:10 | [SSA] s2 | main.rs:156:11:156:12 | s2 | | main.rs:151:9:151:10 | s2 | main.rs:151:9:151:10 | [SSA] s2 | | main.rs:151:14:151:17 | CallExpr | main.rs:151:9:151:10 | s2 | +| main.rs:152:11:152:12 | s1 | main.rs:153:9:153:12 | TupleStructPat | +| main.rs:152:11:152:12 | s1 | main.rs:154:9:154:12 | TupleStructPat | | main.rs:153:11:153:11 | [SSA] n | main.rs:153:22:153:22 | n | | main.rs:153:11:153:11 | n | main.rs:153:11:153:11 | [SSA] n | | main.rs:153:17:153:23 | CallExpr | main.rs:152:5:155:5 | MatchExpr | @@ -135,6 +151,8 @@ | main.rs:154:11:154:11 | n | main.rs:154:11:154:11 | [SSA] n | | main.rs:154:17:154:23 | CallExpr | main.rs:152:5:155:5 | MatchExpr | | main.rs:156:5:159:5 | MatchExpr | main.rs:149:44:160:1 | BlockExpr | +| main.rs:156:11:156:12 | s2 | main.rs:157:9:157:12 | TupleStructPat | +| main.rs:156:11:156:12 | s2 | main.rs:158:9:158:12 | TupleStructPat | | main.rs:157:11:157:11 | [SSA] n | main.rs:157:22:157:22 | n | | main.rs:157:11:157:11 | n | main.rs:157:11:157:11 | [SSA] n | | main.rs:157:17:157:23 | CallExpr | main.rs:156:5:159:5 | MatchExpr | diff --git a/rust/ql/test/library-tests/dataflow/local/inline-flow.expected b/rust/ql/test/library-tests/dataflow/local/inline-flow.expected index 98289b67da64..b8641e064f12 100644 --- a/rust/ql/test/library-tests/dataflow/local/inline-flow.expected +++ b/rust/ql/test/library-tests/dataflow/local/inline-flow.expected @@ -5,6 +5,14 @@ edges | main.rs:31:13:31:21 | CallExpr | main.rs:36:10:36:10 | b | provenance | | | main.rs:45:15:45:23 | CallExpr | main.rs:47:10:47:10 | b | provenance | | | main.rs:53:9:53:17 | CallExpr | main.rs:54:10:54:10 | i | provenance | | +| main.rs:117:14:117:29 | CallExpr [Some] | main.rs:120:9:120:15 | TupleStructPat [Some] | provenance | | +| main.rs:117:19:117:28 | CallExpr | main.rs:117:14:117:29 | CallExpr [Some] | provenance | | +| main.rs:120:9:120:15 | TupleStructPat [Some] | main.rs:120:14:120:14 | n | provenance | | +| main.rs:120:14:120:14 | n | main.rs:120:25:120:25 | n | provenance | | +| main.rs:135:14:135:34 | CallExpr [A] | main.rs:138:9:138:20 | TupleStructPat [A] | provenance | | +| main.rs:135:24:135:33 | CallExpr | main.rs:135:14:135:34 | CallExpr [A] | provenance | | +| main.rs:138:9:138:20 | TupleStructPat [A] | main.rs:138:19:138:19 | n | provenance | | +| main.rs:138:19:138:19 | n | main.rs:138:30:138:30 | n | provenance | | nodes | main.rs:15:10:15:18 | CallExpr | semmle.label | CallExpr | | main.rs:19:13:19:21 | CallExpr | semmle.label | CallExpr | @@ -17,6 +25,16 @@ nodes | main.rs:47:10:47:10 | b | semmle.label | b | | main.rs:53:9:53:17 | CallExpr | semmle.label | CallExpr | | main.rs:54:10:54:10 | i | semmle.label | i | +| main.rs:117:14:117:29 | CallExpr [Some] | semmle.label | CallExpr [Some] | +| main.rs:117:19:117:28 | CallExpr | semmle.label | CallExpr | +| main.rs:120:9:120:15 | TupleStructPat [Some] | semmle.label | TupleStructPat [Some] | +| main.rs:120:14:120:14 | n | semmle.label | n | +| main.rs:120:25:120:25 | n | semmle.label | n | +| main.rs:135:14:135:34 | CallExpr [A] | semmle.label | CallExpr [A] | +| main.rs:135:24:135:33 | CallExpr | semmle.label | CallExpr | +| main.rs:138:9:138:20 | TupleStructPat [A] | semmle.label | TupleStructPat [A] | +| main.rs:138:19:138:19 | n | semmle.label | n | +| main.rs:138:30:138:30 | n | semmle.label | n | subpaths testFailures #select @@ -26,3 +44,5 @@ testFailures | main.rs:36:10:36:10 | b | main.rs:31:13:31:21 | CallExpr | main.rs:36:10:36:10 | b | $@ | main.rs:31:13:31:21 | CallExpr | CallExpr | | main.rs:47:10:47:10 | b | main.rs:45:15:45:23 | CallExpr | main.rs:47:10:47:10 | b | $@ | main.rs:45:15:45:23 | CallExpr | CallExpr | | main.rs:54:10:54:10 | i | main.rs:53:9:53:17 | CallExpr | main.rs:54:10:54:10 | i | $@ | main.rs:53:9:53:17 | CallExpr | CallExpr | +| main.rs:120:25:120:25 | n | main.rs:117:19:117:28 | CallExpr | main.rs:120:25:120:25 | n | $@ | main.rs:117:19:117:28 | CallExpr | CallExpr | +| main.rs:138:30:138:30 | n | main.rs:135:24:135:33 | CallExpr | main.rs:138:30:138:30 | n | $@ | main.rs:135:24:135:33 | CallExpr | CallExpr | diff --git a/rust/ql/test/library-tests/dataflow/local/main.rs b/rust/ql/test/library-tests/dataflow/local/main.rs index 9f31b08f680f..2666339ad59a 100644 --- a/rust/ql/test/library-tests/dataflow/local/main.rs +++ b/rust/ql/test/library-tests/dataflow/local/main.rs @@ -117,7 +117,7 @@ fn option_pattern_match_unqualified() { let s1 = Some(source(14)); let s2 = Some(2); match s1 { - Some(n) => sink(n), // $ MISSING: hasValueFlow=14 + Some(n) => sink(n), // $ hasValueFlow=14 None => sink(0), } match s2 { @@ -135,7 +135,7 @@ fn custom_enum_pattern_match_qualified() { let s1 = MyEnum::A(source(15)); let s2 = MyEnum::B(2); match s1 { - MyEnum::A(n) => sink(n), // $ MISSING: hasValueFlow=15 + MyEnum::A(n) => sink(n), // $ hasValueFlow=15 MyEnum::B(n) => sink(n), } match s2 {