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..0db25f1281dc 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,18 +345,159 @@ module LocalFlow { a.getRhs() = nodeFrom.getCfgNode() and a.getLhs() = nodeTo.getCfgNode() ) + or + exists(MatchExprCfgNode match | + nodeFrom.asExpr() = match.getExpr() and + nodeTo.asPat() = match.getArmPat(_) + ) + or + nodeFrom.asPat().(OrPatCfgNode).getAPat() = nodeTo.asPat() + } +} + +/** + * A reference contained in an object. For example a field in a struct. + */ +abstract class Content extends TContent { + /** Gets a textual representation of this content. */ + abstract string toString(); +} + +/** A variant of an `enum`. */ +abstract private class VariantContent extends Content { + string name; + + bindingset[this, name] + VariantContent() { exists(name) } +} + +/** A tuple variant of an `enum`. */ +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() { + // only print indices when the arity is > 1 + if exists(TVariantTupleContent(crate, path, name, 1)) + then result = name + "(" + i + ")" + else result = name } } -private class DataFlowCallableAlias = DataFlowCallable; +/** A value that represents a set of `Content`s. */ +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`. */ +pragma[nomagic] +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`. */ +pragma[nomagic] +private predicate variantDestructor(TupleStructPat p, VariantContent c, int i) { + pathResolvesToVariant(p.getPath(), c, i) +} + +// Defines a set of aliases needed for the `RustDataFlow` module +private module Aliases { + class DataFlowCallableAlias = DataFlowCallable; -private class ReturnKindAlias = ReturnKind; + class ReturnKindAlias = ReturnKind; -private class DataFlowCallAlias = DataFlowCall; + class DataFlowCallAlias = DataFlowCall; -private class ParameterPositionAlias = ParameterPosition; + class ParameterPositionAlias = ParameterPosition; + + class ContentAlias = Content; + + class ContentSetAlias = ContentSet; +} module RustDataFlow implements InputSig { + private import Aliases + /** * An element, viewed as a node in a data flow graph. Either an expression * (`ExprNode`) or a parameter (`ParameterNode`). @@ -399,55 +543,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 +569,15 @@ module RustDataFlow implements InputSig { predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() } - final class Content = Void; - - predicate forceHighPrecision(Content c) { none() } - - class ContentSet extends TContentSet { - /** Gets a textual representation of this element. */ - string toString() { result = "ContentSet" } + class Content = ContentAlias; - /** 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 +610,34 @@ 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 cs, Node node2) { + exists(Content c | c = cs.(SingletonContentSet).getContent() | + node1.asPat() = + any(TupleStructPatCfgNode pat, int i | + variantDestructor(pat.getPat(), c, 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 cs, Node node2) { + exists(Content c | c = cs.(SingletonContentSet).getContent() | + node2.asExpr() = + any(CallExprCfgNode call, int i | + variantConstructor(call.getCallExpr(), c, i) and + node1.asExpr() = call.getArgument(i) + | + call + ) + ) + } /** * Holds if values stored inside content `c` are cleared at node `n`. For example, @@ -593,8 +704,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 +721,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 +736,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 f679a54f8284..3622aedecd4f 100644 --- a/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected +++ b/rust/ql/test/library-tests/dataflow/local/DataFlowStep.expected @@ -1,3 +1,4 @@ +localStep | main.rs:3:11:3:11 | [SSA] i | main.rs:4:12:4:12 | i | | main.rs:3:11:3:11 | i | main.rs:3:11:3:11 | [SSA] i | | main.rs:3:11:3:16 | ...: i64 | main.rs:3:11:3:11 | i | @@ -33,6 +34,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 | match m { ... } | 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 | match m { ... } | | main.rs:34:17:34:17 | 0 | main.rs:32:13:35:5 | match m { ... } | | main.rs:40:9:40:9 | [SSA] a | main.rs:43:10:43:10 | a | @@ -79,11 +82,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 | ...::Some(...) | 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 | ...::None | | 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 | sink(...) | main.rs:106:5:109:5 | match s1 { ... } | | main.rs:108:25:108:31 | sink(...) | main.rs:106:5:109:5 | match s1 { ... } | | main.rs:110:5:113:5 | match s2 { ... } | main.rs:103:37:114:1 | { ... } | +| 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 | ...::None | | 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 | sink(...) | main.rs:110:5:113:5 | match s2 { ... } | @@ -94,11 +101,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 | Some(...) | 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 | sink(...) | main.rs:119:5:122:5 | match s1 { ... } | | main.rs:121:17:121:23 | sink(...) | main.rs:119:5:122:5 | match s1 { ... } | | main.rs:123:5:126:5 | match s2 { ... } | main.rs:116:39:127:1 | { ... } | +| 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 | sink(...) | main.rs:123:5:126:5 | match s2 { ... } | @@ -109,6 +120,8 @@ | main.rs:136:9:136:10 | [SSA] s2 | main.rs:144:11:144:12 | s2 | | main.rs:136:9:136:10 | s2 | main.rs:136:9:136:10 | [SSA] s2 | | main.rs:136:14:136:25 | ...::B(...) | 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:137:11:137:12 | s1 | main.rs:141:11:141:12 | s1 | | 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 | @@ -116,6 +129,9 @@ | 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 | sink(...) | main.rs:137:5:140:5 | match s1 { ... } | +| main.rs:141:11:141:12 | s1 | main.rs:142:10:142:36 | ... \| ... | +| main.rs:142:10:142:36 | ... \| ... | main.rs:142:10:142:21 | TupleStructPat | +| main.rs:142:10:142:36 | ... \| ... | main.rs:142:25:142:36 | TupleStructPat | | main.rs:142:10:142:36 | [SSA] [match(true)] phi | main.rs:142:47:142:47 | n | | main.rs:142:20:142:20 | [SSA] [input] [match(true)] phi | main.rs:142:10:142:36 | [SSA] [match(true)] phi | | main.rs:142:20:142:20 | [SSA] n | main.rs:142:20:142:20 | [SSA] [input] [match(true)] phi | @@ -125,6 +141,8 @@ | main.rs:142:35:142:35 | n | main.rs:142:35:142:35 | [SSA] n | | main.rs:142:42:142:48 | sink(...) | main.rs:141:5:143:5 | match s1 { ... } | | main.rs:144:5:147:5 | match s2 { ... } | main.rs:134:42:148:1 | { ... } | +| main.rs:144:11:144:12 | s2 | main.rs:145:9:145:20 | TupleStructPat | +| main.rs:144:11:144:12 | s2 | main.rs:146:9:146:20 | TupleStructPat | | main.rs:145:19:145:19 | [SSA] n | main.rs:145:30:145:30 | n | | main.rs:145:19:145:19 | n | main.rs:145:19:145:19 | [SSA] n | | main.rs:145:25:145:31 | sink(...) | main.rs:144:5:147:5 | match s2 { ... } | @@ -137,6 +155,8 @@ | main.rs:154:9:154:10 | [SSA] s2 | main.rs:162:11:162:12 | s2 | | main.rs:154:9:154:10 | s2 | main.rs:154:9:154:10 | [SSA] s2 | | main.rs:154:14:154:17 | B(...) | main.rs:154:9:154:10 | s2 | +| main.rs:155:11:155:12 | s1 | main.rs:156:9:156:12 | TupleStructPat | +| main.rs:155:11:155:12 | s1 | main.rs:157:9:157:12 | TupleStructPat | | main.rs:155:11:155:12 | s1 | main.rs:159:11:159:12 | s1 | | main.rs:156:11:156:11 | [SSA] n | main.rs:156:22:156:22 | n | | main.rs:156:11:156:11 | n | main.rs:156:11:156:11 | [SSA] n | @@ -144,6 +164,9 @@ | 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 | sink(...) | main.rs:155:5:158:5 | match s1 { ... } | +| main.rs:159:11:159:12 | s1 | main.rs:160:10:160:20 | ... \| ... | +| main.rs:160:10:160:20 | ... \| ... | main.rs:160:10:160:13 | TupleStructPat | +| main.rs:160:10:160:20 | ... \| ... | main.rs:160:17:160:20 | TupleStructPat | | main.rs:160:10:160:20 | [SSA] [match(true)] phi | main.rs:160:31:160:31 | n | | main.rs:160:12:160:12 | [SSA] [input] [match(true)] phi | main.rs:160:10:160:20 | [SSA] [match(true)] phi | | main.rs:160:12:160:12 | [SSA] n | main.rs:160:12:160:12 | [SSA] [input] [match(true)] phi | @@ -153,6 +176,8 @@ | main.rs:160:19:160:19 | n | main.rs:160:19:160:19 | [SSA] n | | main.rs:160:26:160:32 | sink(...) | main.rs:159:5:161:5 | match s1 { ... } | | main.rs:162:5:165:5 | match s2 { ... } | main.rs:152:44:166:1 | { ... } | +| main.rs:162:11:162:12 | s2 | main.rs:163:9:163:12 | TupleStructPat | +| main.rs:162:11:162:12 | s2 | main.rs:164:9:164:12 | TupleStructPat | | main.rs:163:11:163:11 | [SSA] n | main.rs:163:22:163:22 | n | | main.rs:163:11:163:11 | n | main.rs:163:11:163:11 | [SSA] n | | main.rs:163:17:163:23 | sink(...) | main.rs:162:5:165:5 | match s2 { ... } | @@ -185,3 +210,19 @@ | main.rs:188:9:188:22 | break ''block 2 | main.rs:184:13:189:5 | 'block: { ... } | | main.rs:188:22:188:22 | 2 | main.rs:188:9:188:22 | break ''block 2 | | main.rs:190:5:190:5 | a | main.rs:183:38:191:1 | { ... } | +storeStep +| main.rs:117:19:117:28 | source(...) | Some | main.rs:117:14:117:29 | Some(...) | +| main.rs:118:19:118:19 | 2 | Some | main.rs:118:14:118:20 | Some(...) | +| main.rs:135:24:135:33 | source(...) | A | main.rs:135:14:135:34 | ...::A(...) | +| main.rs:136:24:136:24 | 2 | B | main.rs:136:14:136:25 | ...::B(...) | +| main.rs:197:27:197:27 | 0 | Some | main.rs:197:22:197:28 | Some(...) | +readStep +| main.rs:33:9:33:15 | TupleStructPat | Some | main.rs:33:14:33:14 | _ | +| main.rs:120:9:120:15 | TupleStructPat | Some | main.rs:120:14:120:14 | n | +| main.rs:124:9:124:15 | TupleStructPat | Some | main.rs:124:14:124:14 | n | +| main.rs:138:9:138:20 | TupleStructPat | A | main.rs:138:19:138:19 | n | +| main.rs:139:9:139:20 | TupleStructPat | B | main.rs:139:19:139:19 | n | +| main.rs:142:10:142:21 | TupleStructPat | A | main.rs:142:20:142:20 | n | +| main.rs:142:25:142:36 | TupleStructPat | B | main.rs:142:35:142:35 | n | +| main.rs:145:9:145:20 | TupleStructPat | A | main.rs:145:19:145:19 | n | +| main.rs:146:9:146:20 | TupleStructPat | B | main.rs:146:19:146:19 | n | diff --git a/rust/ql/test/library-tests/dataflow/local/DataFlowStep.ql b/rust/ql/test/library-tests/dataflow/local/DataFlowStep.ql index 77147a50573a..8bbde28564ac 100644 --- a/rust/ql/test/library-tests/dataflow/local/DataFlowStep.ql +++ b/rust/ql/test/library-tests/dataflow/local/DataFlowStep.ql @@ -1,5 +1,8 @@ import codeql.rust.dataflow.DataFlow +import codeql.rust.dataflow.internal.DataFlowImpl -from DataFlow::Node pred, DataFlow::Node succ -where DataFlow::localFlowStep(pred, succ) -select pred, succ +query predicate localStep = DataFlow::localFlowStep/2; + +query predicate storeStep = RustDataFlow::storeStep/3; + +query predicate readStep = RustDataFlow::readStep/3; 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 f8585809e942..bd271f040ac4 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,17 @@ edges | main.rs:31:13:31:21 | source(...) | main.rs:36:10:36:10 | b | provenance | | | main.rs:45:15:45:23 | source(...) | main.rs:47:10:47:10 | b | provenance | | | main.rs:53:9:53:17 | source(...) | main.rs:54:10:54:10 | i | provenance | | +| main.rs:117:14:117:29 | Some(...) [Some] | main.rs:120:9:120:15 | TupleStructPat [Some] | provenance | | +| main.rs:117:19:117:28 | source(...) | main.rs:117:14:117:29 | Some(...) [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 | ...::A(...) [A] | main.rs:138:9:138:20 | TupleStructPat [A] | provenance | | +| main.rs:135:14:135:34 | ...::A(...) [A] | main.rs:142:10:142:21 | TupleStructPat [A] | provenance | | +| main.rs:135:24:135:33 | source(...) | main.rs:135:14:135:34 | ...::A(...) [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 | | +| main.rs:142:10:142:21 | TupleStructPat [A] | main.rs:142:20:142:20 | n | provenance | | +| main.rs:142:20:142:20 | n | main.rs:142:47:142:47 | n | provenance | | nodes | main.rs:15:10:15:18 | source(...) | semmle.label | source(...) | | main.rs:19:13:19:21 | source(...) | semmle.label | source(...) | @@ -17,6 +28,19 @@ nodes | main.rs:47:10:47:10 | b | semmle.label | b | | main.rs:53:9:53:17 | source(...) | semmle.label | source(...) | | main.rs:54:10:54:10 | i | semmle.label | i | +| main.rs:117:14:117:29 | Some(...) [Some] | semmle.label | Some(...) [Some] | +| main.rs:117:19:117:28 | source(...) | semmle.label | source(...) | +| 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 | ...::A(...) [A] | semmle.label | ...::A(...) [A] | +| main.rs:135:24:135:33 | source(...) | semmle.label | source(...) | +| 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 | +| main.rs:142:10:142:21 | TupleStructPat [A] | semmle.label | TupleStructPat [A] | +| main.rs:142:20:142:20 | n | semmle.label | n | +| main.rs:142:47:142:47 | n | semmle.label | n | subpaths testFailures #select @@ -26,3 +50,6 @@ testFailures | main.rs:36:10:36:10 | b | main.rs:31:13:31:21 | source(...) | main.rs:36:10:36:10 | b | $@ | main.rs:31:13:31:21 | source(...) | source(...) | | main.rs:47:10:47:10 | b | main.rs:45:15:45:23 | source(...) | main.rs:47:10:47:10 | b | $@ | main.rs:45:15:45:23 | source(...) | source(...) | | main.rs:54:10:54:10 | i | main.rs:53:9:53:17 | source(...) | main.rs:54:10:54:10 | i | $@ | main.rs:53:9:53:17 | source(...) | source(...) | +| main.rs:120:25:120:25 | n | main.rs:117:19:117:28 | source(...) | main.rs:120:25:120:25 | n | $@ | main.rs:117:19:117:28 | source(...) | source(...) | +| main.rs:138:30:138:30 | n | main.rs:135:24:135:33 | source(...) | main.rs:138:30:138:30 | n | $@ | main.rs:135:24:135:33 | source(...) | source(...) | +| main.rs:142:47:142:47 | n | main.rs:135:24:135:33 | source(...) | main.rs:142:47:142:47 | n | $@ | main.rs:135:24:135:33 | source(...) | source(...) | diff --git a/rust/ql/test/library-tests/dataflow/local/main.rs b/rust/ql/test/library-tests/dataflow/local/main.rs index 923263554653..16c0a52d6e67 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,11 +135,11 @@ 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 s1 { - (MyEnum::A(n) | MyEnum::B(n)) => sink(n), // $ MISSING: hasValueFlow=15 + (MyEnum::A(n) | MyEnum::B(n)) => sink(n), // $ hasValueFlow=15 } match s2 { MyEnum::A(n) => sink(n),