From 21b03927c54840c224d3f426c90253989575d340 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 12 Apr 2023 17:16:43 +0100 Subject: [PATCH 1/9] Swift: Add failing tests. --- .../dataflow/dataflow/LocalFlow.expected | 31 +++++++++++++++++++ .../dataflow/dataflow/test.swift | 29 +++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected index 516612aa964..8dbfcfd3127 100644 --- a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected +++ b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected @@ -601,3 +601,34 @@ | test.swift:560:7:560:7 | n | test.swift:560:7:560:7 | SSA def(n) | | test.swift:560:11:560:11 | 0 | test.swift:560:7:560:7 | n | | test.swift:561:36:561:36 | n | test.swift:561:35:561:36 | &... | +| test.swift:565:7:565:7 | self | test.swift:565:7:565:7 | SSA def(self) | +| test.swift:567:3:567:3 | SSA def(self) | test.swift:568:5:568:5 | self | +| test.swift:567:3:567:3 | self | test.swift:567:3:567:3 | SSA def(self) | +| test.swift:567:8:567:11 | SSA def(x) | test.swift:568:14:568:14 | x | +| test.swift:567:8:567:11 | x | test.swift:567:8:567:11 | SSA def(x) | +| test.swift:568:5:568:5 | [post] self | test.swift:567:3:569:3 | self[return] | +| test.swift:568:5:568:5 | self | test.swift:567:3:569:3 | self[return] | +| test.swift:573:7:573:7 | SSA def(s) | test.swift:575:13:575:13 | s | +| test.swift:573:7:573:7 | s | test.swift:573:7:573:7 | SSA def(s) | +| test.swift:573:11:573:24 | call to S.init(x:) | test.swift:573:7:573:7 | s | +| test.swift:574:7:574:7 | SSA def(f) | test.swift:575:24:575:24 | f | +| test.swift:574:7:574:7 | f | test.swift:574:7:574:7 | SSA def(f) | +| test.swift:574:11:574:14 | #keyPath(...) | test.swift:574:7:574:7 | f | +| test.swift:574:11:574:14 | #keyPath(...) | test.swift:574:7:574:7 | f | +| test.swift:579:7:579:7 | self | test.swift:579:7:579:7 | SSA def(self) | +| test.swift:581:3:581:3 | SSA def(self) | test.swift:582:5:582:5 | self | +| test.swift:581:3:581:3 | self | test.swift:581:3:581:3 | SSA def(self) | +| test.swift:581:8:581:11 | SSA def(s) | test.swift:582:14:582:14 | s | +| test.swift:581:8:581:11 | s | test.swift:581:8:581:11 | SSA def(s) | +| test.swift:582:5:582:5 | [post] self | test.swift:581:3:583:3 | self[return] | +| test.swift:582:5:582:5 | self | test.swift:581:3:583:3 | self[return] | +| test.swift:587:7:587:7 | SSA def(s) | test.swift:588:18:588:18 | s | +| test.swift:587:7:587:7 | s | test.swift:587:7:587:7 | SSA def(s) | +| test.swift:587:11:587:24 | call to S.init(x:) | test.swift:587:7:587:7 | s | +| test.swift:588:7:588:7 | SSA def(s2) | test.swift:590:13:590:13 | s2 | +| test.swift:588:7:588:7 | s2 | test.swift:588:7:588:7 | SSA def(s2) | +| test.swift:588:12:588:19 | call to S2.init(s:) | test.swift:588:7:588:7 | s2 | +| test.swift:589:7:589:7 | SSA def(f) | test.swift:590:25:590:25 | f | +| test.swift:589:7:589:7 | f | test.swift:589:7:589:7 | SSA def(f) | +| test.swift:589:11:589:17 | #keyPath(...) | test.swift:589:7:589:7 | f | +| test.swift:589:11:589:17 | #keyPath(...) | test.swift:589:7:589:7 | f | diff --git a/swift/ql/test/library-tests/dataflow/dataflow/test.swift b/swift/ql/test/library-tests/dataflow/dataflow/test.swift index 8fa01273d20..60e6964a9de 100644 --- a/swift/ql/test/library-tests/dataflow/dataflow/test.swift +++ b/swift/ql/test/library-tests/dataflow/dataflow/test.swift @@ -560,3 +560,32 @@ func inoutConstructor() { var n = 0 sink(arg: InoutConstructorClass(&n)) } + +struct S { + let x: Int + + init(x: Int) { + self.x = x + } +} + +func testKeyPath() { + let s = S(x: source()) + let f = \S.x + sink(arg: s[keyPath: f]) // $ MISSING: flow=573 +} + +struct S2 { + let s: S + + init(s: S) { + self.s = s + } +} + +func testNestedKeyPath() { + let s = S(x: source()) + let s2 = S2(s: s) + let f = \S2.s.x + sink(arg: s2[keyPath: f]) // $ MISSING: flow=587 +} \ No newline at end of file From f46ea325e870c46af917e5ec63443f3318d8f5fb Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 12 Apr 2023 17:20:46 +0100 Subject: [PATCH 2/9] Swift: Add dataflow through key-path expressios by modeling them as lambdas that perform a sequence of read steps. --- .../lib/codeql/swift/controlflow/CfgNodes.qll | 12 ++ swift/ql/lib/codeql/swift/dataflow/Ssa.qll | 58 ++++++++-- .../dataflow/internal/DataFlowDispatch.qll | 23 ++++ .../dataflow/internal/DataFlowPrivate.qll | 106 +++++++++++++++++- .../swift/elements/KeyPathComponent.qll | 20 ++++ 5 files changed, 206 insertions(+), 13 deletions(-) diff --git a/swift/ql/lib/codeql/swift/controlflow/CfgNodes.qll b/swift/ql/lib/codeql/swift/controlflow/CfgNodes.qll index b1b93a17e4d..f80471b2513 100644 --- a/swift/ql/lib/codeql/swift/controlflow/CfgNodes.qll +++ b/swift/ql/lib/codeql/swift/controlflow/CfgNodes.qll @@ -179,3 +179,15 @@ class ApplyExprCfgNode extends ExprCfgNode { class CallExprCfgNode extends ApplyExprCfgNode { override CallExpr e; } + +class KeyPathApplicationExprCfgNode extends ExprCfgNode { + override KeyPathApplicationExpr e; + + CfgNode getKeyPath() { result.getAst() = e.getKeyPath() } + + CfgNode getBase() { result.getAst() = e.getBase() } +} + +class KeyPathExprCfgNode extends ExprCfgNode { + override KeyPathExpr e; +} diff --git a/swift/ql/lib/codeql/swift/dataflow/Ssa.qll b/swift/ql/lib/codeql/swift/dataflow/Ssa.qll index 16ff1d27924..f065484f6a6 100644 --- a/swift/ql/lib/codeql/swift/dataflow/Ssa.qll +++ b/swift/ql/lib/codeql/swift/dataflow/Ssa.qll @@ -21,7 +21,39 @@ module Ssa { class ExitBasicBlock = BasicBlocks::ExitBasicBlock; - class SourceVariable = VarDecl; + private newtype TSourceVariable = + TNormalSourceVariable(VarDecl v) or + TKeyPathSourceVariable(EntryNode entry) { entry.getScope() instanceof KeyPathExpr } + + abstract class SourceVariable extends TSourceVariable { + abstract string toString(); + + VarDecl asVarDecl() { none() } + + EntryNode asKeyPath() { none() } + + DeclRefExpr getAnAccess() { result.getDecl() = this.asVarDecl() } + } + + private class NormalSourceVariable extends SourceVariable, TNormalSourceVariable { + VarDecl v; + + NormalSourceVariable() { this = TNormalSourceVariable(v) } + + override string toString() { result = v.toString() } + + override VarDecl asVarDecl() { result = v } + } + + private class KeyPathSourceVariable extends SourceVariable, TKeyPathSourceVariable { + EntryNode enter; + + KeyPathSourceVariable() { this = TKeyPathSourceVariable(enter) } + + override string toString() { result = enter.toString() } + + override EntryNode asKeyPath() { result = enter } + } predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) { exists(AssignExpr assign | @@ -40,17 +72,22 @@ module Ssa { // ``` exists(NamedPattern pattern | bb.getNode(i).getNode().asAstNode() = pattern and - v = pattern.getVarDecl() and + v.asVarDecl() = pattern.getVarDecl() and certain = true ) or - v instanceof ParamDecl and - bb.getNode(i).getNode().asAstNode() = v and + exists(ParamDecl p | + p = v.asVarDecl() and + bb.getNode(i).getNode().asAstNode() = p and + certain = true + ) + or + bb.getNode(i) = v.asKeyPath() and certain = true or // Mark the subexpression as a write of the local variable declared in the `TapExpr`. exists(TapExpr tap | - v = tap.getVar() and + v.asVarDecl() = tap.getVar() and bb.getNode(i).getNode().asAstNode() = tap.getSubExpr() and certain = true ) @@ -60,7 +97,7 @@ module Ssa { exists(DeclRefExpr ref | not isLValue(ref) and bb.getNode(i).getNode().asAstNode() = ref and - v = ref.getDecl() and + v.asVarDecl() = ref.getDecl() and certain = true ) or @@ -71,17 +108,16 @@ module Ssa { ) or exists(ExitNode exit, AbstractFunctionDecl func | - func.getAParam() = v or func.getSelfParam() = v - | + [func.getAParam(), func.getSelfParam()] = v.asVarDecl() and bb.getNode(i) = exit and - modifiableParam(v) and + modifiableParam(v.asVarDecl()) and bb.getScope() = func and certain = true ) or // Mark the `TapExpr` as a read of the of the local variable. exists(TapExpr tap | - v = tap.getVar() and + v.asVarDecl() = tap.getVar() and bb.getNode(i).getNode().asAstNode() = tap and certain = true ) @@ -97,7 +133,7 @@ module Ssa { cached ControlFlowNode getARead() { - exists(VarDecl v, SsaInput::BasicBlock bb, int i | + exists(SsaInput::SourceVariable v, SsaInput::BasicBlock bb, int i | SsaImpl::ssaDefReachesRead(v, this, bb, i) and SsaInput::variableRead(bb, i, v, true) and result = bb.getNode(i) diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowDispatch.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowDispatch.qll index 404bd6dfa73..c1685d2d0da 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowDispatch.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowDispatch.qll @@ -74,6 +74,7 @@ newtype TDataFlowCall = TPropertyGetterCall(PropertyGetterCfgNode getter) or TPropertySetterCall(PropertySetterCfgNode setter) or TPropertyObserverCall(PropertyObserverCfgNode observer) or + TKeyPathCall(KeyPathApplicationExprCfgNode keyPathApplication) or TSummaryCall(FlowSummaryImpl::Public::SummarizedCallable c, Node receiver) { FlowSummaryImpl::Private::summaryCallbackRange(c, receiver) } @@ -89,6 +90,9 @@ class DataFlowCall extends TDataFlowCall { /** Gets the underlying source code call, if any. */ ApplyExprCfgNode asCall() { none() } + /** Gets the underlying key-path application node, if any. */ + KeyPathApplicationExprCfgNode asKeyPath() { none() } + /** * Gets the i'th argument of call.class * The qualifier is considered to have index `-1`. @@ -138,6 +142,25 @@ private class NormalCall extends DataFlowCall, TNormalCall { override Location getLocation() { result = apply.getLocation() } } +private class KeyPathCall extends DataFlowCall, TKeyPathCall { + private KeyPathApplicationExprCfgNode apply; + + KeyPathCall() { this = TKeyPathCall(apply) } + + override KeyPathApplicationExprCfgNode asKeyPath() { result = apply } + + override CfgNode getArgument(int i) { + i = -1 and + result = apply.getBase() + } + + override DataFlowCallable getEnclosingCallable() { result = TDataFlowFunc(apply.getScope()) } + + override string toString() { result = apply.toString() } + + override Location getLocation() { result = apply.getLocation() } +} + class PropertyGetterCall extends DataFlowCall, TPropertyGetterCall { private PropertyGetterCfgNode getter; diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll index 25bc8adfccc..4d745a13c33 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll @@ -40,6 +40,22 @@ private class ExprNodeImpl extends ExprNode, NodeImpl { override DataFlowCallable getEnclosingCallable() { result = TDataFlowFunc(n.getScope()) } } +private class KeyPathComponentNodeImpl extends TKeyPathComponentNode, NodeImpl { + KeyPathComponent component; + + KeyPathComponentNodeImpl() { this = TKeyPathComponentNode(component) } + + override Location getLocationImpl() { result = component.getLocation() } + + override string toStringImpl() { result = component.toString() } + + override DataFlowCallable getEnclosingCallable() { + result.asSourceCallable() = component.getKeyPathExpr() + } + + KeyPathComponent getComponent() { result = component } +} + private class PatternNodeImpl extends PatternNode, NodeImpl { override Location getLocationImpl() { result = pattern.getLocation() } @@ -78,6 +94,9 @@ private module Cached { FlowSummaryImpl::Private::summaryNodeRange(c, state) } or TSourceParameterNode(ParamDecl param) or + TKeyPathParameterNode(EntryNode entry) { entry.getScope() instanceof KeyPathExpr } or + TKeyPathReturnNode(ExitNode entry) { entry.getScope() instanceof KeyPathExpr } or + TKeyPathComponentNode(KeyPathComponent component) or TSummaryParameterNode(FlowSummary::SummarizedCallable c, ParameterPosition pos) { FlowSummaryImpl::Private::summaryParameterNodeRange(c, pos) } or @@ -105,7 +124,7 @@ private module Cached { ( nodeTo instanceof InoutReturnNode implies - nodeTo.(InoutReturnNode).getParameter() = def.getSourceVariable() + nodeTo.(InoutReturnNode).getParameter() = def.getSourceVariable().asVarDecl() ) } @@ -135,7 +154,7 @@ private module Cached { ( nodeTo instanceof InoutReturnNode implies - nodeTo.(InoutReturnNode).getParameter() = def.getSourceVariable() + nodeTo.(InoutReturnNode).getParameter() = def.getSourceVariable().asVarDecl() ) or // use-use flow @@ -198,6 +217,11 @@ private module Cached { nodeFrom.asPattern().(TypedPattern).getSubPattern() ] or + // Flow from the unique parameter of a key path expression to + // the first component in the chain. + nodeTo.(KeyPathComponentNodeImpl).getComponent() = + nodeFrom.(KeyPathParameterNode).getComponent(0) + or // flow through a flow summary (extension of `SummaryModelCsv`) FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom, nodeTo, true) } @@ -311,6 +335,28 @@ private module ParameterNodes { override DataFlowCallable getEnclosingCallable() { this.isParameterOf(result, _) } } + + class KeyPathParameterNode extends ParameterNodeImpl, TKeyPathParameterNode { + private EntryNode entry; + + KeyPathParameterNode() { this = TKeyPathParameterNode(entry) } + + override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { + c.asSourceCallable() = entry.getScope() and pos = TThisParameter() + } + + override Location getLocationImpl() { result = entry.getLocation() } + + override string toStringImpl() { result = entry.toString() } + + override DataFlowCallable getEnclosingCallable() { this.isParameterOf(result, _) } + + KeyPathComponent getComponent(int i) { result = entry.getScope().(KeyPathExpr).getComponent(i) } + + KeyPathComponent getAComponent() { result = this.getComponent(_) } + + KeyPathExpr getKeyPathExpr() { result = entry.getScope() } + } } import ParameterNodes @@ -412,6 +458,17 @@ private module ArgumentNodes { FlowSummaryImpl::Private::summaryArgumentNode(call, this, pos) } } + + class KeyPathArgumentNode extends ExprNode, ArgumentNode { + private KeyPathApplicationExprCfgNode keyPath; + + KeyPathArgumentNode() { keyPath.getBase() = this.getCfgNode() } + + override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) { + call.asKeyPath() = keyPath and + pos = TThisArgument() + } + } } import ArgumentNodes @@ -474,6 +531,24 @@ private module ReturnNodes { override ReturnKind getKind() { result = rk } } + + class KeyPathReturnNodeImpl extends ReturnNode, TKeyPathReturnNode, NodeImpl { + ExitNode exit; + + KeyPathReturnNodeImpl() { this = TKeyPathReturnNode(exit) } + + override ReturnKind getKind() { result instanceof NormalReturnKind } + + override ControlFlowNode getCfgNode() { result = exit } + + override DataFlowCallable getEnclosingCallable() { result.asSourceCallable() = exit.getScope() } + + override Location getLocationImpl() { result = exit.getLocation() } + + override string toStringImpl() { result = exit.toString() } + + KeyPathExpr getKeyPathExpr() { result = exit.getScope() } + } } import ReturnNodes @@ -495,6 +570,16 @@ private module OutNodes { } } + class KeyPathOutNode extends OutNode, ExprNodeImpl { + KeyPathApplicationExprCfgNode keyPath; + + KeyPathOutNode() { keyPath = this.getCfgNode() } + + override DataFlowCall getCall(ReturnKind kind) { + result.asKeyPath() = keyPath and kind instanceof NormalReturnKind + } + } + class SummaryOutNode extends OutNode, SummaryNode { SummaryOutNode() { FlowSummaryImpl::Private::summaryOutNode(_, this, _) } @@ -658,6 +743,20 @@ predicate readStep(Node node1, ContentSet c, Node node2) { node2.asPattern() = pat.getSubPattern() and c instanceof OptionalSomeContentSet ) + or + // read of a component in a key-path expression chain + exists(KeyPathComponent component, FieldDecl f | + component = node1.(KeyPathComponentNodeImpl).getComponent() and + f = component.getDeclRef() and + c.isSingleton(any(Content::FieldContent ct | ct.getField() = f)) + | + // the next node is either the next element in the chain + node2.(KeyPathComponentNodeImpl).getComponent() = component.getNextComponent() + or + // or the return node, if this is the last component in the chain + not exists(component.getNextComponent()) and + node2.(KeyPathReturnNodeImpl).getKeyPathExpr() = component.getKeyPathExpr() + ) } /** @@ -786,6 +885,9 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) { or kind = TLambdaCallKind() and receiver = call.(SummaryCall).getReceiver() + or + kind = TLambdaCallKind() and + receiver.asExpr() = call.asKeyPath().getExpr().(KeyPathApplicationExpr).getKeyPath() } /** Extra data-flow steps needed for lambda flow analysis. */ diff --git a/swift/ql/lib/codeql/swift/elements/KeyPathComponent.qll b/swift/ql/lib/codeql/swift/elements/KeyPathComponent.qll index e8ce561c84b..f2580c08426 100644 --- a/swift/ql/lib/codeql/swift/elements/KeyPathComponent.qll +++ b/swift/ql/lib/codeql/swift/elements/KeyPathComponent.qll @@ -1,4 +1,5 @@ private import codeql.swift.generated.KeyPathComponent +private import swift class KeyPathComponent extends Generated::KeyPathComponent { /** @@ -35,4 +36,23 @@ class KeyPathComponent extends Generated::KeyPathComponent { * Tuple indexing like `.1`. */ predicate isTupleIndexing() { getKind() = 9 } + + /** Gets the underlying key-path expression which this is a component of. */ + KeyPathExpr getKeyPathExpr() { result.getAComponent() = this } + + /** Holds if this component is the i'th component of the underling key-path expression. */ + predicate hasIndex(int i) { any(KeyPathExpr e).getComponent(i) = this } + + /** Gets the next component of the underlying key-path expression. */ + KeyPathComponent getNextComponent() { + exists(int i, KeyPathExpr e | + hasKeyPathExprAndIndex(e, i, this) and + hasKeyPathExprAndIndex(e, i + 1, result) + ) + } +} + +pragma[nomagic] +private predicate hasKeyPathExprAndIndex(KeyPathExpr e, int i, KeyPathComponent c) { + e.getComponent(i) = c } From 184cb74cd045dac9d728bb45612681491e8309ff Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 12 Apr 2023 17:21:08 +0100 Subject: [PATCH 3/9] Swift: Accept test changes. --- .../dataflow/dataflow/DataFlow.expected | 64 +++++++++++++++++++ .../dataflow/dataflow/LocalFlow.expected | 2 + .../dataflow/dataflow/test.swift | 4 +- 3 files changed, 68 insertions(+), 2 deletions(-) diff --git a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected index 0eea49ff838..4eb958ffa6a 100644 --- a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected +++ b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected @@ -247,6 +247,32 @@ edges | test.swift:549:24:549:32 | call to source3() : | test.swift:549:13:549:33 | call to MyClass.init(s:) [str] : | | test.swift:550:13:550:41 | call to Self.init(contentsOfFile:) [str] : | test.swift:535:9:535:9 | self [str] : | | test.swift:550:13:550:41 | call to Self.init(contentsOfFile:) [str] : | test.swift:550:13:550:43 | .str | +| test.swift:567:8:567:11 | x : | test.swift:568:14:568:14 | x : | +| test.swift:568:5:568:5 | [post] self [x] : | test.swift:567:3:569:3 | self[return] [x] : | +| test.swift:568:14:568:14 | x : | test.swift:568:5:568:5 | [post] self [x] : | +| test.swift:573:11:573:24 | call to S.init(x:) [x] : | test.swift:575:13:575:13 | s [x] : | +| test.swift:573:16:573:23 | call to source() : | test.swift:567:8:567:11 | x : | +| test.swift:573:16:573:23 | call to source() : | test.swift:573:11:573:24 | call to S.init(x:) [x] : | +| test.swift:574:11:574:14 | enter #keyPath(...) [x] : | test.swift:574:14:574:14 | KeyPathComponent [x] : | +| test.swift:574:14:574:14 | KeyPathComponent [x] : | test.swift:574:11:574:14 | exit #keyPath(...) : | +| test.swift:575:13:575:13 | s [x] : | test.swift:574:11:574:14 | enter #keyPath(...) [x] : | +| test.swift:575:13:575:13 | s [x] : | test.swift:575:13:575:25 | \\...[...] | +| test.swift:575:13:575:13 | s [x] : | test.swift:575:13:575:25 | \\...[...] | +| test.swift:581:8:581:11 | s [x] : | test.swift:582:14:582:14 | s [x] : | +| test.swift:582:5:582:5 | [post] self [s, x] : | test.swift:581:3:583:3 | self[return] [s, x] : | +| test.swift:582:14:582:14 | s [x] : | test.swift:582:5:582:5 | [post] self [s, x] : | +| test.swift:587:11:587:24 | call to S.init(x:) [x] : | test.swift:588:18:588:18 | s [x] : | +| test.swift:587:16:587:23 | call to source() : | test.swift:567:8:567:11 | x : | +| test.swift:587:16:587:23 | call to source() : | test.swift:587:11:587:24 | call to S.init(x:) [x] : | +| test.swift:588:12:588:19 | call to S2.init(s:) [s, x] : | test.swift:590:13:590:13 | s2 [s, x] : | +| test.swift:588:18:588:18 | s [x] : | test.swift:581:8:581:11 | s [x] : | +| test.swift:588:18:588:18 | s [x] : | test.swift:588:12:588:19 | call to S2.init(s:) [s, x] : | +| test.swift:589:11:589:17 | enter #keyPath(...) [s, x] : | test.swift:589:15:589:15 | KeyPathComponent [s, x] : | +| test.swift:589:15:589:15 | KeyPathComponent [s, x] : | test.swift:589:17:589:17 | KeyPathComponent [x] : | +| test.swift:589:17:589:17 | KeyPathComponent [x] : | test.swift:589:11:589:17 | exit #keyPath(...) : | +| test.swift:590:13:590:13 | s2 [s, x] : | test.swift:589:11:589:17 | enter #keyPath(...) [s, x] : | +| test.swift:590:13:590:13 | s2 [s, x] : | test.swift:590:13:590:26 | \\...[...] | +| test.swift:590:13:590:13 | s2 [s, x] : | test.swift:590:13:590:26 | \\...[...] | nodes | file://:0:0:0:0 | .a [x] : | semmle.label | .a [x] : | | file://:0:0:0:0 | .str : | semmle.label | .str : | @@ -514,6 +540,33 @@ nodes | test.swift:549:24:549:32 | call to source3() : | semmle.label | call to source3() : | | test.swift:550:13:550:41 | call to Self.init(contentsOfFile:) [str] : | semmle.label | call to Self.init(contentsOfFile:) [str] : | | test.swift:550:13:550:43 | .str | semmle.label | .str | +| test.swift:567:3:569:3 | self[return] [x] : | semmle.label | self[return] [x] : | +| test.swift:567:8:567:11 | x : | semmle.label | x : | +| test.swift:568:5:568:5 | [post] self [x] : | semmle.label | [post] self [x] : | +| test.swift:568:14:568:14 | x : | semmle.label | x : | +| test.swift:573:11:573:24 | call to S.init(x:) [x] : | semmle.label | call to S.init(x:) [x] : | +| test.swift:573:16:573:23 | call to source() : | semmle.label | call to source() : | +| test.swift:574:11:574:14 | enter #keyPath(...) [x] : | semmle.label | enter #keyPath(...) [x] : | +| test.swift:574:11:574:14 | exit #keyPath(...) : | semmle.label | exit #keyPath(...) : | +| test.swift:574:14:574:14 | KeyPathComponent [x] : | semmle.label | KeyPathComponent [x] : | +| test.swift:575:13:575:13 | s [x] : | semmle.label | s [x] : | +| test.swift:575:13:575:25 | \\...[...] | semmle.label | \\...[...] | +| test.swift:575:13:575:25 | \\...[...] | semmle.label | \\...[...] | +| test.swift:581:3:583:3 | self[return] [s, x] : | semmle.label | self[return] [s, x] : | +| test.swift:581:8:581:11 | s [x] : | semmle.label | s [x] : | +| test.swift:582:5:582:5 | [post] self [s, x] : | semmle.label | [post] self [s, x] : | +| test.swift:582:14:582:14 | s [x] : | semmle.label | s [x] : | +| test.swift:587:11:587:24 | call to S.init(x:) [x] : | semmle.label | call to S.init(x:) [x] : | +| test.swift:587:16:587:23 | call to source() : | semmle.label | call to source() : | +| test.swift:588:12:588:19 | call to S2.init(s:) [s, x] : | semmle.label | call to S2.init(s:) [s, x] : | +| test.swift:588:18:588:18 | s [x] : | semmle.label | s [x] : | +| test.swift:589:11:589:17 | enter #keyPath(...) [s, x] : | semmle.label | enter #keyPath(...) [s, x] : | +| test.swift:589:11:589:17 | exit #keyPath(...) : | semmle.label | exit #keyPath(...) : | +| test.swift:589:15:589:15 | KeyPathComponent [s, x] : | semmle.label | KeyPathComponent [s, x] : | +| test.swift:589:17:589:17 | KeyPathComponent [x] : | semmle.label | KeyPathComponent [x] : | +| test.swift:590:13:590:13 | s2 [s, x] : | semmle.label | s2 [s, x] : | +| test.swift:590:13:590:26 | \\...[...] | semmle.label | \\...[...] | +| test.swift:590:13:590:26 | \\...[...] | semmle.label | \\...[...] | subpaths | test.swift:75:21:75:22 | &... : | test.swift:65:16:65:28 | arg1 : | test.swift:65:1:70:1 | arg2[return] : | test.swift:75:31:75:32 | [post] &... : | | test.swift:114:19:114:19 | arg : | test.swift:109:9:109:14 | arg : | test.swift:110:12:110:12 | arg : | test.swift:114:12:114:22 | call to ... : | @@ -551,6 +604,13 @@ subpaths | test.swift:549:13:549:33 | call to MyClass.init(s:) [str] : | test.swift:535:9:535:9 | self [str] : | file://:0:0:0:0 | .str : | test.swift:549:13:549:35 | .str | | test.swift:549:24:549:32 | call to source3() : | test.swift:536:10:536:13 | s : | test.swift:536:5:538:5 | self[return] [str] : | test.swift:549:13:549:33 | call to MyClass.init(s:) [str] : | | test.swift:550:13:550:41 | call to Self.init(contentsOfFile:) [str] : | test.swift:535:9:535:9 | self [str] : | file://:0:0:0:0 | .str : | test.swift:550:13:550:43 | .str | +| test.swift:573:16:573:23 | call to source() : | test.swift:567:8:567:11 | x : | test.swift:567:3:569:3 | self[return] [x] : | test.swift:573:11:573:24 | call to S.init(x:) [x] : | +| test.swift:575:13:575:13 | s [x] : | test.swift:574:11:574:14 | enter #keyPath(...) [x] : | test.swift:574:11:574:14 | exit #keyPath(...) : | test.swift:575:13:575:25 | \\...[...] | +| test.swift:575:13:575:13 | s [x] : | test.swift:574:11:574:14 | enter #keyPath(...) [x] : | test.swift:574:11:574:14 | exit #keyPath(...) : | test.swift:575:13:575:25 | \\...[...] | +| test.swift:587:16:587:23 | call to source() : | test.swift:567:8:567:11 | x : | test.swift:567:3:569:3 | self[return] [x] : | test.swift:587:11:587:24 | call to S.init(x:) [x] : | +| test.swift:588:18:588:18 | s [x] : | test.swift:581:8:581:11 | s [x] : | test.swift:581:3:583:3 | self[return] [s, x] : | test.swift:588:12:588:19 | call to S2.init(s:) [s, x] : | +| test.swift:590:13:590:13 | s2 [s, x] : | test.swift:589:11:589:17 | enter #keyPath(...) [s, x] : | test.swift:589:11:589:17 | exit #keyPath(...) : | test.swift:590:13:590:26 | \\...[...] | +| test.swift:590:13:590:13 | s2 [s, x] : | test.swift:589:11:589:17 | enter #keyPath(...) [s, x] : | test.swift:589:11:589:17 | exit #keyPath(...) : | test.swift:590:13:590:26 | \\...[...] | #select | test.swift:7:15:7:15 | t1 | test.swift:6:19:6:26 | call to source() : | test.swift:7:15:7:15 | t1 | result | | test.swift:9:15:9:15 | t1 | test.swift:6:19:6:26 | call to source() : | test.swift:9:15:9:15 | t1 | result | @@ -621,3 +681,7 @@ subpaths | test.swift:544:17:544:17 | .str | test.swift:543:20:543:28 | call to source3() : | test.swift:544:17:544:17 | .str | result | | test.swift:549:13:549:35 | .str | test.swift:549:24:549:32 | call to source3() : | test.swift:549:13:549:35 | .str | result | | test.swift:550:13:550:43 | .str | test.swift:543:20:543:28 | call to source3() : | test.swift:550:13:550:43 | .str | result | +| test.swift:575:13:575:25 | \\...[...] | test.swift:573:16:573:23 | call to source() : | test.swift:575:13:575:25 | \\...[...] | result | +| test.swift:575:13:575:25 | \\...[...] | test.swift:573:16:573:23 | call to source() : | test.swift:575:13:575:25 | \\...[...] | result | +| test.swift:590:13:590:26 | \\...[...] | test.swift:587:16:587:23 | call to source() : | test.swift:590:13:590:26 | \\...[...] | result | +| test.swift:590:13:590:26 | \\...[...] | test.swift:587:16:587:23 | call to source() : | test.swift:590:13:590:26 | \\...[...] | result | diff --git a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected index 8dbfcfd3127..1dca89b6d33 100644 --- a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected +++ b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected @@ -615,6 +615,7 @@ | test.swift:574:7:574:7 | f | test.swift:574:7:574:7 | SSA def(f) | | test.swift:574:11:574:14 | #keyPath(...) | test.swift:574:7:574:7 | f | | test.swift:574:11:574:14 | #keyPath(...) | test.swift:574:7:574:7 | f | +| test.swift:574:11:574:14 | enter #keyPath(...) | test.swift:574:14:574:14 | KeyPathComponent | | test.swift:579:7:579:7 | self | test.swift:579:7:579:7 | SSA def(self) | | test.swift:581:3:581:3 | SSA def(self) | test.swift:582:5:582:5 | self | | test.swift:581:3:581:3 | self | test.swift:581:3:581:3 | SSA def(self) | @@ -632,3 +633,4 @@ | test.swift:589:7:589:7 | f | test.swift:589:7:589:7 | SSA def(f) | | test.swift:589:11:589:17 | #keyPath(...) | test.swift:589:7:589:7 | f | | test.swift:589:11:589:17 | #keyPath(...) | test.swift:589:7:589:7 | f | +| test.swift:589:11:589:17 | enter #keyPath(...) | test.swift:589:15:589:15 | KeyPathComponent | diff --git a/swift/ql/test/library-tests/dataflow/dataflow/test.swift b/swift/ql/test/library-tests/dataflow/dataflow/test.swift index 60e6964a9de..51a549bde25 100644 --- a/swift/ql/test/library-tests/dataflow/dataflow/test.swift +++ b/swift/ql/test/library-tests/dataflow/dataflow/test.swift @@ -572,7 +572,7 @@ struct S { func testKeyPath() { let s = S(x: source()) let f = \S.x - sink(arg: s[keyPath: f]) // $ MISSING: flow=573 + sink(arg: s[keyPath: f]) // $ flow=573 } struct S2 { @@ -587,5 +587,5 @@ func testNestedKeyPath() { let s = S(x: source()) let s2 = S2(s: s) let f = \S2.s.x - sink(arg: s2[keyPath: f]) // $ MISSING: flow=587 + sink(arg: s2[keyPath: f]) // $ flow=587 } \ No newline at end of file From 859b3051b796f8754ae52fa4a94934baa5557d72 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 13 Apr 2023 13:12:02 +0100 Subject: [PATCH 4/9] Swift: Add consistency queries to CFG tests. --- swift/ql/lib/codeql/swift/dataflow/Ssa.qll | 5 ++- .../controlflow/graph/consistency.expected | 36 +++++++++++++++++++ .../controlflow/graph/consistency.ql | 1 + 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 swift/ql/test/library-tests/controlflow/graph/consistency.expected create mode 100644 swift/ql/test/library-tests/controlflow/graph/consistency.ql diff --git a/swift/ql/lib/codeql/swift/dataflow/Ssa.qll b/swift/ql/lib/codeql/swift/dataflow/Ssa.qll index f065484f6a6..44c07c3c5a8 100644 --- a/swift/ql/lib/codeql/swift/dataflow/Ssa.qll +++ b/swift/ql/lib/codeql/swift/dataflow/Ssa.qll @@ -124,7 +124,10 @@ module Ssa { } } - private module SsaImpl = SsaImplCommon::Make; + /** + * INTERNAL: Do not use. + */ + module SsaImpl = SsaImplCommon::Make; cached class Definition extends SsaImpl::Definition { diff --git a/swift/ql/test/library-tests/controlflow/graph/consistency.expected b/swift/ql/test/library-tests/controlflow/graph/consistency.expected new file mode 100644 index 00000000000..5d304ad8aff --- /dev/null +++ b/swift/ql/test/library-tests/controlflow/graph/consistency.expected @@ -0,0 +1,36 @@ +nonUniqueSetRepresentation +breakInvariant2 +breakInvariant3 +breakInvariant4 +breakInvariant5 +multipleSuccessors +| cfg.swift:33:28:33:28 | ... is ... | no-match | cfg.swift:33:49:33:60 | call to isZero(x:) | +| cfg.swift:33:28:33:28 | ... is ... | no-match | cfg.swift:35:5:37:3 | case ... | +| cfg.swift:144:10:144:10 | =~ ... | no-match | cfg.swift:144:18:144:34 | ... .&&(_:_:) ... | +| cfg.swift:144:10:144:10 | =~ ... | no-match | cfg.swift:146:5:147:14 | case ... | +| cfg.swift:456:19:456:24 | #keyPath(...) | successor | cfg.swift:456:3:456:24 | var ... = ... | +| cfg.swift:456:19:456:24 | #keyPath(...) | successor | cfg.swift:456:19:456:24 | exit #keyPath(...) (normal) | +| cfg.swift:457:22:457:31 | #keyPath(...) | successor | cfg.swift:457:3:457:31 | var ... = ... | +| cfg.swift:457:22:457:31 | #keyPath(...) | successor | cfg.swift:457:22:457:31 | exit #keyPath(...) (normal) | +| cfg.swift:458:28:458:37 | #keyPath(...) | successor | cfg.swift:458:3:458:37 | var ... = ... | +| cfg.swift:458:28:458:37 | #keyPath(...) | successor | cfg.swift:458:28:458:37 | exit #keyPath(...) (normal) | +| cfg.swift:459:22:459:31 | #keyPath(...) | successor | cfg.swift:459:3:459:31 | var ... = ... | +| cfg.swift:459:22:459:31 | #keyPath(...) | successor | cfg.swift:459:22:459:31 | exit #keyPath(...) (normal) | +| cfg.swift:515:6:515:28 | #available | false | cfg.swift:515:42:515:46 | iOS 12 | +| cfg.swift:515:6:515:28 | #available | false | cfg.swift:519:10:519:10 | x | +| file://:0:0:0:0 | $interpolation | successor | cfg.swift:40:11:40:11 | OpaqueValueExpr | +| file://:0:0:0:0 | $interpolation | successor | cfg.swift:40:12:40:12 | .appendLiteral(_:) | +| file://:0:0:0:0 | $interpolation | successor | cfg.swift:263:10:263:10 | OpaqueValueExpr | +| file://:0:0:0:0 | $interpolation | successor | cfg.swift:263:11:263:11 | .appendLiteral(_:) | +simpleAndNormalSuccessors +deadEnd +| cfg.swift:33:49:33:60 | call to isZero(x:) | +| cfg.swift:144:18:144:34 | ... .&&(_:_:) ... | +| cfg.swift:464:7:464:7 | apply_kpGet_mayB_x | +| cfg.swift:464:7:464:7 | apply_kpGet_mayB_x | +| cfg.swift:464:7:464:7 | apply_kpGet_mayB_x | +| cfg.swift:464:7:464:7 | apply_kpGet_mayB_x | +| file://:0:0:0:0 | ... = ... | +| file://:0:0:0:0 | ... = ... | +nonUniqueSplitKind +nonUniqueListOrder diff --git a/swift/ql/test/library-tests/controlflow/graph/consistency.ql b/swift/ql/test/library-tests/controlflow/graph/consistency.ql new file mode 100644 index 00000000000..36521fa8131 --- /dev/null +++ b/swift/ql/test/library-tests/controlflow/graph/consistency.ql @@ -0,0 +1 @@ +import codeql.swift.controlflow.internal.ControlFlowGraphImplShared::Consistency From 33bc7eabbb9986444d79a7630159c5ace301b1ed Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 12 Apr 2023 17:22:23 +0100 Subject: [PATCH 5/9] Swift: Fix CFG for key-path expressions. --- .../internal/ControlFlowGraphImpl.qll | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowGraphImpl.qll b/swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowGraphImpl.qll index 80f07564747..422f98a89c4 100644 --- a/swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowGraphImpl.qll +++ b/swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowGraphImpl.qll @@ -58,7 +58,7 @@ module CfgScope { } private class KeyPathScope extends Range_ instanceof KeyPathExpr { - AstControlFlowTree tree; + KeyPathControlFlowTree tree; KeyPathScope() { tree.getAst() = this } @@ -76,6 +76,12 @@ module CfgScope { final override predicate exit(ControlFlowElement last, Completion c) { last(tree, last, c) } } + + private class KeyPathControlFlowTree extends StandardPostOrderTree, KeyPathElement { + final override ControlFlowElement getChildElement(int i) { + result.asAstNode() = expr.getComponent(i) + } + } } /** Holds if `first` is first executed when entering `scope`. */ @@ -88,6 +94,14 @@ predicate succExit(CfgScope::Range_ scope, ControlFlowElement last, Completion c scope.exit(last, c) } +private class KeyPathComponentTree extends AstStandardPostOrderTree { + override KeyPathComponent ast; + + final override ControlFlowElement getChildElement(int i) { + result.asAstNode() = ast.getSubscriptArgument(i).getExpr().getFullyConverted() + } +} + /** * Control-flow for statements. */ From 68cdc3b48e0354bd8c6076d3b1639062fa1b1746 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 12 Apr 2023 17:22:41 +0100 Subject: [PATCH 6/9] Swift: Accept test changes. --- .../controlflow/graph/Cfg.expected | 483 ++---------------- .../controlflow/graph/consistency.expected | 12 - .../dataflow/dataflow/DataFlow.expected | 8 - .../dataflow/dataflow/LocalFlow.expected | 2 - 4 files changed, 43 insertions(+), 462 deletions(-) diff --git a/swift/ql/test/library-tests/controlflow/graph/Cfg.expected b/swift/ql/test/library-tests/controlflow/graph/Cfg.expected index ae67debf690..4384bcf4b1e 100644 --- a/swift/ql/test/library-tests/controlflow/graph/Cfg.expected +++ b/swift/ql/test/library-tests/controlflow/graph/Cfg.expected @@ -5680,12 +5680,6 @@ cfg.swift: # 456| var ... = ... #-----| -> kpGet_b_x -# 456| var ... = ... -#-----| -> kpGet_b_x - -# 456| kpGet_b_x -#-----| -> kpGet_bs_0_x - # 456| kpGet_b_x #-----| -> kpGet_bs_0_x @@ -5693,193 +5687,122 @@ cfg.swift: #-----| match -> #keyPath(...) # 456| #keyPath(...) -#-----| -> var ... = ... +#-----| -> exit #keyPath(...) (normal) # 456| #keyPath(...) #-----| -> var ... = ... -#-----| -> exit #keyPath(...) (normal) # 456| enter #keyPath(...) -#-----| -> #keyPath(...) +#-----| -> KeyPathComponent # 456| exit #keyPath(...) # 456| exit #keyPath(...) (normal) #-----| -> exit #keyPath(...) -# 457| var ... = ... -#-----| -> kpGet_bs_0_x +# 456| KeyPathComponent +#-----| -> KeyPathComponent + +# 456| KeyPathComponent +#-----| -> #keyPath(...) # 457| var ... = ... #-----| -> kpGet_bs_0_x -# 457| var ... = ... -#-----| -> kpGet_bs_0_x - -# 457| kpGet_bs_0_x -#-----| -> kpGet_mayB_force_x - -# 457| kpGet_bs_0_x -#-----| -> kpGet_mayB_force_x - # 457| kpGet_bs_0_x #-----| -> kpGet_mayB_force_x # 457| kpGet_bs_0_x #-----| match -> #keyPath(...) -# 457| kpGet_bs_0_x -#-----| match -> #keyPath(...) - # 457| #keyPath(...) -#-----| -> var ... = ... - -# 457| #keyPath(...) -#-----| -> var ... = ... - -# 457| #keyPath(...) -#-----| -> var ... = ... #-----| -> exit #keyPath(...) (normal) +# 457| #keyPath(...) +#-----| -> var ... = ... + # 457| enter #keyPath(...) -#-----| -> #keyPath(...) +#-----| -> KeyPathComponent # 457| exit #keyPath(...) # 457| exit #keyPath(...) (normal) #-----| -> exit #keyPath(...) -# 458| var ... = ... -#-----| -> kpGet_mayB_force_x +# 457| KeyPathComponent +#-----| -> 0 + +# 457| KeyPathComponent +#-----| -> KeyPathComponent + +# 457| 0 +#-----| -> KeyPathComponent + +# 457| KeyPathComponent +#-----| -> #keyPath(...) # 458| var ... = ... #-----| -> kpGet_mayB_force_x -# 458| var ... = ... -#-----| -> kpGet_mayB_force_x - -# 458| var ... = ... -#-----| -> kpGet_mayB_force_x - -# 458| kpGet_mayB_force_x -#-----| -> kpGet_mayB_x - -# 458| kpGet_mayB_force_x -#-----| -> kpGet_mayB_x - -# 458| kpGet_mayB_force_x -#-----| -> kpGet_mayB_x - # 458| kpGet_mayB_force_x #-----| -> kpGet_mayB_x # 458| kpGet_mayB_force_x #-----| match -> #keyPath(...) -# 458| kpGet_mayB_force_x -#-----| match -> #keyPath(...) - -# 458| kpGet_mayB_force_x -#-----| match -> #keyPath(...) - # 458| #keyPath(...) -#-----| -> var ... = ... - -# 458| #keyPath(...) -#-----| -> var ... = ... - -# 458| #keyPath(...) -#-----| -> var ... = ... - -# 458| #keyPath(...) -#-----| -> var ... = ... #-----| -> exit #keyPath(...) (normal) +# 458| #keyPath(...) +#-----| -> var ... = ... + # 458| enter #keyPath(...) -#-----| -> #keyPath(...) +#-----| -> KeyPathComponent # 458| exit #keyPath(...) # 458| exit #keyPath(...) (normal) #-----| -> exit #keyPath(...) -# 459| var ... = ... -#-----| -> kpGet_mayB_x +# 458| KeyPathComponent +#-----| -> KeyPathComponent + +# 458| KeyPathComponent +#-----| -> KeyPathComponent + +# 458| KeyPathComponent +#-----| -> #keyPath(...) # 459| var ... = ... #-----| -> kpGet_mayB_x -# 459| var ... = ... -#-----| -> kpGet_mayB_x - -# 459| var ... = ... -#-----| -> kpGet_mayB_x - -# 459| var ... = ... -#-----| -> kpGet_mayB_x - -# 459| kpGet_mayB_x -#-----| -> apply_kpGet_b_x - -# 459| kpGet_mayB_x -#-----| -> apply_kpGet_b_x - -# 459| kpGet_mayB_x -#-----| -> apply_kpGet_b_x - -# 459| kpGet_mayB_x -#-----| -> apply_kpGet_b_x - # 459| kpGet_mayB_x #-----| -> apply_kpGet_b_x # 459| kpGet_mayB_x #-----| match -> #keyPath(...) -# 459| kpGet_mayB_x -#-----| match -> #keyPath(...) - -# 459| kpGet_mayB_x -#-----| match -> #keyPath(...) - -# 459| kpGet_mayB_x -#-----| match -> #keyPath(...) - # 459| #keyPath(...) -#-----| -> var ... = ... - -# 459| #keyPath(...) -#-----| -> var ... = ... - -# 459| #keyPath(...) -#-----| -> var ... = ... - -# 459| #keyPath(...) -#-----| -> var ... = ... - -# 459| #keyPath(...) -#-----| -> var ... = ... #-----| -> exit #keyPath(...) (normal) +# 459| #keyPath(...) +#-----| -> var ... = ... + # 459| enter #keyPath(...) -#-----| -> #keyPath(...) +#-----| -> KeyPathComponent # 459| exit #keyPath(...) # 459| exit #keyPath(...) (normal) #-----| -> exit #keyPath(...) -# 461| var ... = ... -#-----| -> apply_kpGet_b_x +# 459| KeyPathComponent +#-----| -> KeyPathComponent -# 461| var ... = ... -#-----| -> apply_kpGet_b_x +# 459| KeyPathComponent +#-----| -> KeyPathComponent -# 461| var ... = ... -#-----| -> apply_kpGet_b_x - -# 461| var ... = ... -#-----| -> apply_kpGet_b_x +# 459| KeyPathComponent # 461| var ... = ... #-----| -> apply_kpGet_b_x @@ -5887,401 +5810,81 @@ cfg.swift: # 461| apply_kpGet_b_x #-----| -> apply_kpGet_bs_0_x -# 461| apply_kpGet_b_x -#-----| -> apply_kpGet_bs_0_x - -# 461| apply_kpGet_b_x -#-----| -> apply_kpGet_bs_0_x - -# 461| apply_kpGet_b_x -#-----| -> apply_kpGet_bs_0_x - -# 461| apply_kpGet_b_x -#-----| -> apply_kpGet_bs_0_x - # 461| apply_kpGet_b_x #-----| match -> a -# 461| apply_kpGet_b_x -#-----| match -> a - -# 461| apply_kpGet_b_x -#-----| match -> a - -# 461| apply_kpGet_b_x -#-----| match -> a - -# 461| apply_kpGet_b_x -#-----| match -> a - -# 461| a -#-----| -> kpGet_b_x - -# 461| a -#-----| -> kpGet_b_x - -# 461| a -#-----| -> kpGet_b_x - -# 461| a -#-----| -> kpGet_b_x - # 461| a #-----| -> kpGet_b_x # 461| \...[...] #-----| -> var ... = ... -# 461| \...[...] -#-----| -> var ... = ... - -# 461| \...[...] -#-----| -> var ... = ... - -# 461| \...[...] -#-----| -> var ... = ... - -# 461| \...[...] -#-----| -> var ... = ... - -# 461| (WritableKeyPath) ... -#-----| -> \...[...] - -# 461| (WritableKeyPath) ... -#-----| -> \...[...] - -# 461| (WritableKeyPath) ... -#-----| -> \...[...] - -# 461| (WritableKeyPath) ... -#-----| -> \...[...] - # 461| (WritableKeyPath) ... #-----| -> \...[...] # 461| kpGet_b_x #-----| -> (WritableKeyPath) ... -# 461| kpGet_b_x -#-----| -> (WritableKeyPath) ... - -# 461| kpGet_b_x -#-----| -> (WritableKeyPath) ... - -# 461| kpGet_b_x -#-----| -> (WritableKeyPath) ... - -# 461| kpGet_b_x -#-----| -> (WritableKeyPath) ... - -# 462| var ... = ... -#-----| -> apply_kpGet_bs_0_x - -# 462| var ... = ... -#-----| -> apply_kpGet_bs_0_x - -# 462| var ... = ... -#-----| -> apply_kpGet_bs_0_x - -# 462| var ... = ... -#-----| -> apply_kpGet_bs_0_x - # 462| var ... = ... #-----| -> apply_kpGet_bs_0_x # 462| apply_kpGet_bs_0_x #-----| -> apply_kpGet_mayB_force_x -# 462| apply_kpGet_bs_0_x -#-----| -> apply_kpGet_mayB_force_x - -# 462| apply_kpGet_bs_0_x -#-----| -> apply_kpGet_mayB_force_x - -# 462| apply_kpGet_bs_0_x -#-----| -> apply_kpGet_mayB_force_x - -# 462| apply_kpGet_bs_0_x -#-----| -> apply_kpGet_mayB_force_x - # 462| apply_kpGet_bs_0_x #-----| match -> a -# 462| apply_kpGet_bs_0_x -#-----| match -> a - -# 462| apply_kpGet_bs_0_x -#-----| match -> a - -# 462| apply_kpGet_bs_0_x -#-----| match -> a - -# 462| apply_kpGet_bs_0_x -#-----| match -> a - -# 462| a -#-----| -> kpGet_bs_0_x - -# 462| a -#-----| -> kpGet_bs_0_x - -# 462| a -#-----| -> kpGet_bs_0_x - -# 462| a -#-----| -> kpGet_bs_0_x - # 462| a #-----| -> kpGet_bs_0_x # 462| \...[...] #-----| -> var ... = ... -# 462| \...[...] -#-----| -> var ... = ... - -# 462| \...[...] -#-----| -> var ... = ... - -# 462| \...[...] -#-----| -> var ... = ... - -# 462| \...[...] -#-----| -> var ... = ... - -# 462| (WritableKeyPath) ... -#-----| -> \...[...] - -# 462| (WritableKeyPath) ... -#-----| -> \...[...] - -# 462| (WritableKeyPath) ... -#-----| -> \...[...] - -# 462| (WritableKeyPath) ... -#-----| -> \...[...] - # 462| (WritableKeyPath) ... #-----| -> \...[...] # 462| kpGet_bs_0_x #-----| -> (WritableKeyPath) ... -# 462| kpGet_bs_0_x -#-----| -> (WritableKeyPath) ... - -# 462| kpGet_bs_0_x -#-----| -> (WritableKeyPath) ... - -# 462| kpGet_bs_0_x -#-----| -> (WritableKeyPath) ... - -# 462| kpGet_bs_0_x -#-----| -> (WritableKeyPath) ... - -# 463| var ... = ... -#-----| -> apply_kpGet_mayB_force_x - -# 463| var ... = ... -#-----| -> apply_kpGet_mayB_force_x - -# 463| var ... = ... -#-----| -> apply_kpGet_mayB_force_x - -# 463| var ... = ... -#-----| -> apply_kpGet_mayB_force_x - # 463| var ... = ... #-----| -> apply_kpGet_mayB_force_x # 463| apply_kpGet_mayB_force_x #-----| -> apply_kpGet_mayB_x -# 463| apply_kpGet_mayB_force_x -#-----| -> apply_kpGet_mayB_x - -# 463| apply_kpGet_mayB_force_x -#-----| -> apply_kpGet_mayB_x - -# 463| apply_kpGet_mayB_force_x -#-----| -> apply_kpGet_mayB_x - -# 463| apply_kpGet_mayB_force_x -#-----| -> apply_kpGet_mayB_x - # 463| apply_kpGet_mayB_force_x #-----| match -> a -# 463| apply_kpGet_mayB_force_x -#-----| match -> a - -# 463| apply_kpGet_mayB_force_x -#-----| match -> a - -# 463| apply_kpGet_mayB_force_x -#-----| match -> a - -# 463| apply_kpGet_mayB_force_x -#-----| match -> a - -# 463| a -#-----| -> kpGet_mayB_force_x - -# 463| a -#-----| -> kpGet_mayB_force_x - -# 463| a -#-----| -> kpGet_mayB_force_x - -# 463| a -#-----| -> kpGet_mayB_force_x - # 463| a #-----| -> kpGet_mayB_force_x # 463| \...[...] #-----| -> var ... = ... -# 463| \...[...] -#-----| -> var ... = ... - -# 463| \...[...] -#-----| -> var ... = ... - -# 463| \...[...] -#-----| -> var ... = ... - -# 463| \...[...] -#-----| -> var ... = ... - -# 463| (WritableKeyPath) ... -#-----| -> \...[...] - -# 463| (WritableKeyPath) ... -#-----| -> \...[...] - -# 463| (WritableKeyPath) ... -#-----| -> \...[...] - -# 463| (WritableKeyPath) ... -#-----| -> \...[...] - # 463| (WritableKeyPath) ... #-----| -> \...[...] # 463| kpGet_mayB_force_x #-----| -> (WritableKeyPath) ... -# 463| kpGet_mayB_force_x -#-----| -> (WritableKeyPath) ... - -# 463| kpGet_mayB_force_x -#-----| -> (WritableKeyPath) ... - -# 463| kpGet_mayB_force_x -#-----| -> (WritableKeyPath) ... - -# 463| kpGet_mayB_force_x -#-----| -> (WritableKeyPath) ... - -# 464| var ... = ... -#-----| -> apply_kpGet_mayB_x - -# 464| var ... = ... -#-----| -> apply_kpGet_mayB_x - -# 464| var ... = ... -#-----| -> apply_kpGet_mayB_x - -# 464| var ... = ... -#-----| -> apply_kpGet_mayB_x - # 464| var ... = ... #-----| -> apply_kpGet_mayB_x # 464| apply_kpGet_mayB_x #-----| -> exit test(a:) (normal) -# 464| apply_kpGet_mayB_x - -# 464| apply_kpGet_mayB_x - -# 464| apply_kpGet_mayB_x - -# 464| apply_kpGet_mayB_x - # 464| apply_kpGet_mayB_x #-----| match -> a -# 464| apply_kpGet_mayB_x -#-----| match -> a - -# 464| apply_kpGet_mayB_x -#-----| match -> a - -# 464| apply_kpGet_mayB_x -#-----| match -> a - -# 464| apply_kpGet_mayB_x -#-----| match -> a - -# 464| a -#-----| -> kpGet_mayB_x - -# 464| a -#-----| -> kpGet_mayB_x - -# 464| a -#-----| -> kpGet_mayB_x - -# 464| a -#-----| -> kpGet_mayB_x - # 464| a #-----| -> kpGet_mayB_x # 464| \...[...] #-----| -> var ... = ... -# 464| \...[...] -#-----| -> var ... = ... - -# 464| \...[...] -#-----| -> var ... = ... - -# 464| \...[...] -#-----| -> var ... = ... - -# 464| \...[...] -#-----| -> var ... = ... - # 464| (KeyPath) ... #-----| -> \...[...] -# 464| (KeyPath) ... -#-----| -> \...[...] - -# 464| (KeyPath) ... -#-----| -> \...[...] - -# 464| (KeyPath) ... -#-----| -> \...[...] - -# 464| (KeyPath) ... -#-----| -> \...[...] - -# 464| kpGet_mayB_x -#-----| -> (KeyPath) ... - -# 464| kpGet_mayB_x -#-----| -> (KeyPath) ... - -# 464| kpGet_mayB_x -#-----| -> (KeyPath) ... - -# 464| kpGet_mayB_x -#-----| -> (KeyPath) ... - # 464| kpGet_mayB_x #-----| -> (KeyPath) ... diff --git a/swift/ql/test/library-tests/controlflow/graph/consistency.expected b/swift/ql/test/library-tests/controlflow/graph/consistency.expected index 5d304ad8aff..0440ab97c1a 100644 --- a/swift/ql/test/library-tests/controlflow/graph/consistency.expected +++ b/swift/ql/test/library-tests/controlflow/graph/consistency.expected @@ -8,14 +8,6 @@ multipleSuccessors | cfg.swift:33:28:33:28 | ... is ... | no-match | cfg.swift:35:5:37:3 | case ... | | cfg.swift:144:10:144:10 | =~ ... | no-match | cfg.swift:144:18:144:34 | ... .&&(_:_:) ... | | cfg.swift:144:10:144:10 | =~ ... | no-match | cfg.swift:146:5:147:14 | case ... | -| cfg.swift:456:19:456:24 | #keyPath(...) | successor | cfg.swift:456:3:456:24 | var ... = ... | -| cfg.swift:456:19:456:24 | #keyPath(...) | successor | cfg.swift:456:19:456:24 | exit #keyPath(...) (normal) | -| cfg.swift:457:22:457:31 | #keyPath(...) | successor | cfg.swift:457:3:457:31 | var ... = ... | -| cfg.swift:457:22:457:31 | #keyPath(...) | successor | cfg.swift:457:22:457:31 | exit #keyPath(...) (normal) | -| cfg.swift:458:28:458:37 | #keyPath(...) | successor | cfg.swift:458:3:458:37 | var ... = ... | -| cfg.swift:458:28:458:37 | #keyPath(...) | successor | cfg.swift:458:28:458:37 | exit #keyPath(...) (normal) | -| cfg.swift:459:22:459:31 | #keyPath(...) | successor | cfg.swift:459:3:459:31 | var ... = ... | -| cfg.swift:459:22:459:31 | #keyPath(...) | successor | cfg.swift:459:22:459:31 | exit #keyPath(...) (normal) | | cfg.swift:515:6:515:28 | #available | false | cfg.swift:515:42:515:46 | iOS 12 | | cfg.swift:515:6:515:28 | #available | false | cfg.swift:519:10:519:10 | x | | file://:0:0:0:0 | $interpolation | successor | cfg.swift:40:11:40:11 | OpaqueValueExpr | @@ -26,10 +18,6 @@ simpleAndNormalSuccessors deadEnd | cfg.swift:33:49:33:60 | call to isZero(x:) | | cfg.swift:144:18:144:34 | ... .&&(_:_:) ... | -| cfg.swift:464:7:464:7 | apply_kpGet_mayB_x | -| cfg.swift:464:7:464:7 | apply_kpGet_mayB_x | -| cfg.swift:464:7:464:7 | apply_kpGet_mayB_x | -| cfg.swift:464:7:464:7 | apply_kpGet_mayB_x | | file://:0:0:0:0 | ... = ... | | file://:0:0:0:0 | ... = ... | nonUniqueSplitKind diff --git a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected index 4eb958ffa6a..ac414dd22d2 100644 --- a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected +++ b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected @@ -257,7 +257,6 @@ edges | test.swift:574:14:574:14 | KeyPathComponent [x] : | test.swift:574:11:574:14 | exit #keyPath(...) : | | test.swift:575:13:575:13 | s [x] : | test.swift:574:11:574:14 | enter #keyPath(...) [x] : | | test.swift:575:13:575:13 | s [x] : | test.swift:575:13:575:25 | \\...[...] | -| test.swift:575:13:575:13 | s [x] : | test.swift:575:13:575:25 | \\...[...] | | test.swift:581:8:581:11 | s [x] : | test.swift:582:14:582:14 | s [x] : | | test.swift:582:5:582:5 | [post] self [s, x] : | test.swift:581:3:583:3 | self[return] [s, x] : | | test.swift:582:14:582:14 | s [x] : | test.swift:582:5:582:5 | [post] self [s, x] : | @@ -272,7 +271,6 @@ edges | test.swift:589:17:589:17 | KeyPathComponent [x] : | test.swift:589:11:589:17 | exit #keyPath(...) : | | test.swift:590:13:590:13 | s2 [s, x] : | test.swift:589:11:589:17 | enter #keyPath(...) [s, x] : | | test.swift:590:13:590:13 | s2 [s, x] : | test.swift:590:13:590:26 | \\...[...] | -| test.swift:590:13:590:13 | s2 [s, x] : | test.swift:590:13:590:26 | \\...[...] | nodes | file://:0:0:0:0 | .a [x] : | semmle.label | .a [x] : | | file://:0:0:0:0 | .str : | semmle.label | .str : | @@ -551,7 +549,6 @@ nodes | test.swift:574:14:574:14 | KeyPathComponent [x] : | semmle.label | KeyPathComponent [x] : | | test.swift:575:13:575:13 | s [x] : | semmle.label | s [x] : | | test.swift:575:13:575:25 | \\...[...] | semmle.label | \\...[...] | -| test.swift:575:13:575:25 | \\...[...] | semmle.label | \\...[...] | | test.swift:581:3:583:3 | self[return] [s, x] : | semmle.label | self[return] [s, x] : | | test.swift:581:8:581:11 | s [x] : | semmle.label | s [x] : | | test.swift:582:5:582:5 | [post] self [s, x] : | semmle.label | [post] self [s, x] : | @@ -566,7 +563,6 @@ nodes | test.swift:589:17:589:17 | KeyPathComponent [x] : | semmle.label | KeyPathComponent [x] : | | test.swift:590:13:590:13 | s2 [s, x] : | semmle.label | s2 [s, x] : | | test.swift:590:13:590:26 | \\...[...] | semmle.label | \\...[...] | -| test.swift:590:13:590:26 | \\...[...] | semmle.label | \\...[...] | subpaths | test.swift:75:21:75:22 | &... : | test.swift:65:16:65:28 | arg1 : | test.swift:65:1:70:1 | arg2[return] : | test.swift:75:31:75:32 | [post] &... : | | test.swift:114:19:114:19 | arg : | test.swift:109:9:109:14 | arg : | test.swift:110:12:110:12 | arg : | test.swift:114:12:114:22 | call to ... : | @@ -606,11 +602,9 @@ subpaths | test.swift:550:13:550:41 | call to Self.init(contentsOfFile:) [str] : | test.swift:535:9:535:9 | self [str] : | file://:0:0:0:0 | .str : | test.swift:550:13:550:43 | .str | | test.swift:573:16:573:23 | call to source() : | test.swift:567:8:567:11 | x : | test.swift:567:3:569:3 | self[return] [x] : | test.swift:573:11:573:24 | call to S.init(x:) [x] : | | test.swift:575:13:575:13 | s [x] : | test.swift:574:11:574:14 | enter #keyPath(...) [x] : | test.swift:574:11:574:14 | exit #keyPath(...) : | test.swift:575:13:575:25 | \\...[...] | -| test.swift:575:13:575:13 | s [x] : | test.swift:574:11:574:14 | enter #keyPath(...) [x] : | test.swift:574:11:574:14 | exit #keyPath(...) : | test.swift:575:13:575:25 | \\...[...] | | test.swift:587:16:587:23 | call to source() : | test.swift:567:8:567:11 | x : | test.swift:567:3:569:3 | self[return] [x] : | test.swift:587:11:587:24 | call to S.init(x:) [x] : | | test.swift:588:18:588:18 | s [x] : | test.swift:581:8:581:11 | s [x] : | test.swift:581:3:583:3 | self[return] [s, x] : | test.swift:588:12:588:19 | call to S2.init(s:) [s, x] : | | test.swift:590:13:590:13 | s2 [s, x] : | test.swift:589:11:589:17 | enter #keyPath(...) [s, x] : | test.swift:589:11:589:17 | exit #keyPath(...) : | test.swift:590:13:590:26 | \\...[...] | -| test.swift:590:13:590:13 | s2 [s, x] : | test.swift:589:11:589:17 | enter #keyPath(...) [s, x] : | test.swift:589:11:589:17 | exit #keyPath(...) : | test.swift:590:13:590:26 | \\...[...] | #select | test.swift:7:15:7:15 | t1 | test.swift:6:19:6:26 | call to source() : | test.swift:7:15:7:15 | t1 | result | | test.swift:9:15:9:15 | t1 | test.swift:6:19:6:26 | call to source() : | test.swift:9:15:9:15 | t1 | result | @@ -682,6 +676,4 @@ subpaths | test.swift:549:13:549:35 | .str | test.swift:549:24:549:32 | call to source3() : | test.swift:549:13:549:35 | .str | result | | test.swift:550:13:550:43 | .str | test.swift:543:20:543:28 | call to source3() : | test.swift:550:13:550:43 | .str | result | | test.swift:575:13:575:25 | \\...[...] | test.swift:573:16:573:23 | call to source() : | test.swift:575:13:575:25 | \\...[...] | result | -| test.swift:575:13:575:25 | \\...[...] | test.swift:573:16:573:23 | call to source() : | test.swift:575:13:575:25 | \\...[...] | result | -| test.swift:590:13:590:26 | \\...[...] | test.swift:587:16:587:23 | call to source() : | test.swift:590:13:590:26 | \\...[...] | result | | test.swift:590:13:590:26 | \\...[...] | test.swift:587:16:587:23 | call to source() : | test.swift:590:13:590:26 | \\...[...] | result | diff --git a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected index 1dca89b6d33..824622e770d 100644 --- a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected +++ b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected @@ -614,7 +614,6 @@ | test.swift:574:7:574:7 | SSA def(f) | test.swift:575:24:575:24 | f | | test.swift:574:7:574:7 | f | test.swift:574:7:574:7 | SSA def(f) | | test.swift:574:11:574:14 | #keyPath(...) | test.swift:574:7:574:7 | f | -| test.swift:574:11:574:14 | #keyPath(...) | test.swift:574:7:574:7 | f | | test.swift:574:11:574:14 | enter #keyPath(...) | test.swift:574:14:574:14 | KeyPathComponent | | test.swift:579:7:579:7 | self | test.swift:579:7:579:7 | SSA def(self) | | test.swift:581:3:581:3 | SSA def(self) | test.swift:582:5:582:5 | self | @@ -632,5 +631,4 @@ | test.swift:589:7:589:7 | SSA def(f) | test.swift:590:25:590:25 | f | | test.swift:589:7:589:7 | f | test.swift:589:7:589:7 | SSA def(f) | | test.swift:589:11:589:17 | #keyPath(...) | test.swift:589:7:589:7 | f | -| test.swift:589:11:589:17 | #keyPath(...) | test.swift:589:7:589:7 | f | | test.swift:589:11:589:17 | enter #keyPath(...) | test.swift:589:15:589:15 | KeyPathComponent | From f32d77b36cd2b9419b0e36021941627bf197f42d Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 12 Apr 2023 17:52:35 +0100 Subject: [PATCH 7/9] Swift: Add QLDoc. --- swift/ql/lib/codeql/swift/controlflow/CfgNodes.qll | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/swift/ql/lib/codeql/swift/controlflow/CfgNodes.qll b/swift/ql/lib/codeql/swift/controlflow/CfgNodes.qll index f80471b2513..872fced8a03 100644 --- a/swift/ql/lib/codeql/swift/controlflow/CfgNodes.qll +++ b/swift/ql/lib/codeql/swift/controlflow/CfgNodes.qll @@ -180,14 +180,24 @@ class CallExprCfgNode extends ApplyExprCfgNode { override CallExpr e; } +/** A control-flow node that wraps a key-path application. */ class KeyPathApplicationExprCfgNode extends ExprCfgNode { override KeyPathApplicationExpr e; + /** + * Gets the control-flow node that wraps the key-path of + * this control-flow element. + */ CfgNode getKeyPath() { result.getAst() = e.getKeyPath() } + /** + * Gets the control-flow node that wraps the base of + * this control-flow element. + */ CfgNode getBase() { result.getAst() = e.getBase() } } +/** A control-flow node that wraps a key-path expression. */ class KeyPathExprCfgNode extends ExprCfgNode { override KeyPathExpr e; } From f9d5e56d9c02e7cebdcd6605242e70cc15296fad Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 13 Apr 2023 13:22:07 +0100 Subject: [PATCH 8/9] s/entry/exit --- swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll index 4d745a13c33..804d21db45d 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll @@ -95,7 +95,7 @@ private module Cached { } or TSourceParameterNode(ParamDecl param) or TKeyPathParameterNode(EntryNode entry) { entry.getScope() instanceof KeyPathExpr } or - TKeyPathReturnNode(ExitNode entry) { entry.getScope() instanceof KeyPathExpr } or + TKeyPathReturnNode(ExitNode exit) { exit.getScope() instanceof KeyPathExpr } or TKeyPathComponentNode(KeyPathComponent component) or TSummaryParameterNode(FlowSummary::SummarizedCallable c, ParameterPosition pos) { FlowSummaryImpl::Private::summaryParameterNodeRange(c, pos) From 231b0fcab2ede5efbadfd26aef4a430a3cbda72a Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Tue, 18 Apr 2023 12:01:08 +0100 Subject: [PATCH 9/9] Swift: Add more tests. --- .../dataflow/dataflow/DataFlow.expected | 76 +++++++++++-------- .../dataflow/dataflow/LocalFlow.expected | 64 +++++++++++----- .../dataflow/dataflow/test.swift | 26 ++++++- 3 files changed, 116 insertions(+), 50 deletions(-) diff --git a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected index ac414dd22d2..ec958991a9e 100644 --- a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected +++ b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected @@ -251,26 +251,31 @@ edges | test.swift:568:5:568:5 | [post] self [x] : | test.swift:567:3:569:3 | self[return] [x] : | | test.swift:568:14:568:14 | x : | test.swift:568:5:568:5 | [post] self [x] : | | test.swift:573:11:573:24 | call to S.init(x:) [x] : | test.swift:575:13:575:13 | s [x] : | +| test.swift:573:11:573:24 | call to S.init(x:) [x] : | test.swift:578:13:578:13 | s [x] : | | test.swift:573:16:573:23 | call to source() : | test.swift:567:8:567:11 | x : | | test.swift:573:16:573:23 | call to source() : | test.swift:573:11:573:24 | call to S.init(x:) [x] : | | test.swift:574:11:574:14 | enter #keyPath(...) [x] : | test.swift:574:14:574:14 | KeyPathComponent [x] : | | test.swift:574:14:574:14 | KeyPathComponent [x] : | test.swift:574:11:574:14 | exit #keyPath(...) : | | test.swift:575:13:575:13 | s [x] : | test.swift:574:11:574:14 | enter #keyPath(...) [x] : | | test.swift:575:13:575:13 | s [x] : | test.swift:575:13:575:25 | \\...[...] | -| test.swift:581:8:581:11 | s [x] : | test.swift:582:14:582:14 | s [x] : | -| test.swift:582:5:582:5 | [post] self [s, x] : | test.swift:581:3:583:3 | self[return] [s, x] : | -| test.swift:582:14:582:14 | s [x] : | test.swift:582:5:582:5 | [post] self [s, x] : | -| test.swift:587:11:587:24 | call to S.init(x:) [x] : | test.swift:588:18:588:18 | s [x] : | -| test.swift:587:16:587:23 | call to source() : | test.swift:567:8:567:11 | x : | -| test.swift:587:16:587:23 | call to source() : | test.swift:587:11:587:24 | call to S.init(x:) [x] : | -| test.swift:588:12:588:19 | call to S2.init(s:) [s, x] : | test.swift:590:13:590:13 | s2 [s, x] : | -| test.swift:588:18:588:18 | s [x] : | test.swift:581:8:581:11 | s [x] : | -| test.swift:588:18:588:18 | s [x] : | test.swift:588:12:588:19 | call to S2.init(s:) [s, x] : | -| test.swift:589:11:589:17 | enter #keyPath(...) [s, x] : | test.swift:589:15:589:15 | KeyPathComponent [s, x] : | -| test.swift:589:15:589:15 | KeyPathComponent [s, x] : | test.swift:589:17:589:17 | KeyPathComponent [x] : | -| test.swift:589:17:589:17 | KeyPathComponent [x] : | test.swift:589:11:589:17 | exit #keyPath(...) : | -| test.swift:590:13:590:13 | s2 [s, x] : | test.swift:589:11:589:17 | enter #keyPath(...) [s, x] : | -| test.swift:590:13:590:13 | s2 [s, x] : | test.swift:590:13:590:26 | \\...[...] | +| test.swift:577:36:577:38 | enter #keyPath(...) [x] : | test.swift:577:38:577:38 | KeyPathComponent [x] : | +| test.swift:577:38:577:38 | KeyPathComponent [x] : | test.swift:577:36:577:38 | exit #keyPath(...) : | +| test.swift:578:13:578:13 | s [x] : | test.swift:577:36:577:38 | enter #keyPath(...) [x] : | +| test.swift:578:13:578:13 | s [x] : | test.swift:578:13:578:32 | \\...[...] | +| test.swift:584:8:584:11 | s [x] : | test.swift:585:14:585:14 | s [x] : | +| test.swift:585:5:585:5 | [post] self [s, x] : | test.swift:584:3:586:3 | self[return] [s, x] : | +| test.swift:585:14:585:14 | s [x] : | test.swift:585:5:585:5 | [post] self [s, x] : | +| test.swift:590:11:590:24 | call to S.init(x:) [x] : | test.swift:591:18:591:18 | s [x] : | +| test.swift:590:16:590:23 | call to source() : | test.swift:567:8:567:11 | x : | +| test.swift:590:16:590:23 | call to source() : | test.swift:590:11:590:24 | call to S.init(x:) [x] : | +| test.swift:591:12:591:19 | call to S2.init(s:) [s, x] : | test.swift:593:13:593:13 | s2 [s, x] : | +| test.swift:591:18:591:18 | s [x] : | test.swift:584:8:584:11 | s [x] : | +| test.swift:591:18:591:18 | s [x] : | test.swift:591:12:591:19 | call to S2.init(s:) [s, x] : | +| test.swift:592:11:592:17 | enter #keyPath(...) [s, x] : | test.swift:592:15:592:15 | KeyPathComponent [s, x] : | +| test.swift:592:15:592:15 | KeyPathComponent [s, x] : | test.swift:592:17:592:17 | KeyPathComponent [x] : | +| test.swift:592:17:592:17 | KeyPathComponent [x] : | test.swift:592:11:592:17 | exit #keyPath(...) : | +| test.swift:593:13:593:13 | s2 [s, x] : | test.swift:592:11:592:17 | enter #keyPath(...) [s, x] : | +| test.swift:593:13:593:13 | s2 [s, x] : | test.swift:593:13:593:26 | \\...[...] | nodes | file://:0:0:0:0 | .a [x] : | semmle.label | .a [x] : | | file://:0:0:0:0 | .str : | semmle.label | .str : | @@ -549,20 +554,25 @@ nodes | test.swift:574:14:574:14 | KeyPathComponent [x] : | semmle.label | KeyPathComponent [x] : | | test.swift:575:13:575:13 | s [x] : | semmle.label | s [x] : | | test.swift:575:13:575:25 | \\...[...] | semmle.label | \\...[...] | -| test.swift:581:3:583:3 | self[return] [s, x] : | semmle.label | self[return] [s, x] : | -| test.swift:581:8:581:11 | s [x] : | semmle.label | s [x] : | -| test.swift:582:5:582:5 | [post] self [s, x] : | semmle.label | [post] self [s, x] : | -| test.swift:582:14:582:14 | s [x] : | semmle.label | s [x] : | -| test.swift:587:11:587:24 | call to S.init(x:) [x] : | semmle.label | call to S.init(x:) [x] : | -| test.swift:587:16:587:23 | call to source() : | semmle.label | call to source() : | -| test.swift:588:12:588:19 | call to S2.init(s:) [s, x] : | semmle.label | call to S2.init(s:) [s, x] : | -| test.swift:588:18:588:18 | s [x] : | semmle.label | s [x] : | -| test.swift:589:11:589:17 | enter #keyPath(...) [s, x] : | semmle.label | enter #keyPath(...) [s, x] : | -| test.swift:589:11:589:17 | exit #keyPath(...) : | semmle.label | exit #keyPath(...) : | -| test.swift:589:15:589:15 | KeyPathComponent [s, x] : | semmle.label | KeyPathComponent [s, x] : | -| test.swift:589:17:589:17 | KeyPathComponent [x] : | semmle.label | KeyPathComponent [x] : | -| test.swift:590:13:590:13 | s2 [s, x] : | semmle.label | s2 [s, x] : | -| test.swift:590:13:590:26 | \\...[...] | semmle.label | \\...[...] | +| test.swift:577:36:577:38 | enter #keyPath(...) [x] : | semmle.label | enter #keyPath(...) [x] : | +| test.swift:577:36:577:38 | exit #keyPath(...) : | semmle.label | exit #keyPath(...) : | +| test.swift:577:38:577:38 | KeyPathComponent [x] : | semmle.label | KeyPathComponent [x] : | +| test.swift:578:13:578:13 | s [x] : | semmle.label | s [x] : | +| test.swift:578:13:578:32 | \\...[...] | semmle.label | \\...[...] | +| test.swift:584:3:586:3 | self[return] [s, x] : | semmle.label | self[return] [s, x] : | +| test.swift:584:8:584:11 | s [x] : | semmle.label | s [x] : | +| test.swift:585:5:585:5 | [post] self [s, x] : | semmle.label | [post] self [s, x] : | +| test.swift:585:14:585:14 | s [x] : | semmle.label | s [x] : | +| test.swift:590:11:590:24 | call to S.init(x:) [x] : | semmle.label | call to S.init(x:) [x] : | +| test.swift:590:16:590:23 | call to source() : | semmle.label | call to source() : | +| test.swift:591:12:591:19 | call to S2.init(s:) [s, x] : | semmle.label | call to S2.init(s:) [s, x] : | +| test.swift:591:18:591:18 | s [x] : | semmle.label | s [x] : | +| test.swift:592:11:592:17 | enter #keyPath(...) [s, x] : | semmle.label | enter #keyPath(...) [s, x] : | +| test.swift:592:11:592:17 | exit #keyPath(...) : | semmle.label | exit #keyPath(...) : | +| test.swift:592:15:592:15 | KeyPathComponent [s, x] : | semmle.label | KeyPathComponent [s, x] : | +| test.swift:592:17:592:17 | KeyPathComponent [x] : | semmle.label | KeyPathComponent [x] : | +| test.swift:593:13:593:13 | s2 [s, x] : | semmle.label | s2 [s, x] : | +| test.swift:593:13:593:26 | \\...[...] | semmle.label | \\...[...] | subpaths | test.swift:75:21:75:22 | &... : | test.swift:65:16:65:28 | arg1 : | test.swift:65:1:70:1 | arg2[return] : | test.swift:75:31:75:32 | [post] &... : | | test.swift:114:19:114:19 | arg : | test.swift:109:9:109:14 | arg : | test.swift:110:12:110:12 | arg : | test.swift:114:12:114:22 | call to ... : | @@ -602,9 +612,10 @@ subpaths | test.swift:550:13:550:41 | call to Self.init(contentsOfFile:) [str] : | test.swift:535:9:535:9 | self [str] : | file://:0:0:0:0 | .str : | test.swift:550:13:550:43 | .str | | test.swift:573:16:573:23 | call to source() : | test.swift:567:8:567:11 | x : | test.swift:567:3:569:3 | self[return] [x] : | test.swift:573:11:573:24 | call to S.init(x:) [x] : | | test.swift:575:13:575:13 | s [x] : | test.swift:574:11:574:14 | enter #keyPath(...) [x] : | test.swift:574:11:574:14 | exit #keyPath(...) : | test.swift:575:13:575:25 | \\...[...] | -| test.swift:587:16:587:23 | call to source() : | test.swift:567:8:567:11 | x : | test.swift:567:3:569:3 | self[return] [x] : | test.swift:587:11:587:24 | call to S.init(x:) [x] : | -| test.swift:588:18:588:18 | s [x] : | test.swift:581:8:581:11 | s [x] : | test.swift:581:3:583:3 | self[return] [s, x] : | test.swift:588:12:588:19 | call to S2.init(s:) [s, x] : | -| test.swift:590:13:590:13 | s2 [s, x] : | test.swift:589:11:589:17 | enter #keyPath(...) [s, x] : | test.swift:589:11:589:17 | exit #keyPath(...) : | test.swift:590:13:590:26 | \\...[...] | +| test.swift:578:13:578:13 | s [x] : | test.swift:577:36:577:38 | enter #keyPath(...) [x] : | test.swift:577:36:577:38 | exit #keyPath(...) : | test.swift:578:13:578:32 | \\...[...] | +| test.swift:590:16:590:23 | call to source() : | test.swift:567:8:567:11 | x : | test.swift:567:3:569:3 | self[return] [x] : | test.swift:590:11:590:24 | call to S.init(x:) [x] : | +| test.swift:591:18:591:18 | s [x] : | test.swift:584:8:584:11 | s [x] : | test.swift:584:3:586:3 | self[return] [s, x] : | test.swift:591:12:591:19 | call to S2.init(s:) [s, x] : | +| test.swift:593:13:593:13 | s2 [s, x] : | test.swift:592:11:592:17 | enter #keyPath(...) [s, x] : | test.swift:592:11:592:17 | exit #keyPath(...) : | test.swift:593:13:593:26 | \\...[...] | #select | test.swift:7:15:7:15 | t1 | test.swift:6:19:6:26 | call to source() : | test.swift:7:15:7:15 | t1 | result | | test.swift:9:15:9:15 | t1 | test.swift:6:19:6:26 | call to source() : | test.swift:9:15:9:15 | t1 | result | @@ -676,4 +687,5 @@ subpaths | test.swift:549:13:549:35 | .str | test.swift:549:24:549:32 | call to source3() : | test.swift:549:13:549:35 | .str | result | | test.swift:550:13:550:43 | .str | test.swift:543:20:543:28 | call to source3() : | test.swift:550:13:550:43 | .str | result | | test.swift:575:13:575:25 | \\...[...] | test.swift:573:16:573:23 | call to source() : | test.swift:575:13:575:25 | \\...[...] | result | -| test.swift:590:13:590:26 | \\...[...] | test.swift:587:16:587:23 | call to source() : | test.swift:590:13:590:26 | \\...[...] | result | +| test.swift:578:13:578:32 | \\...[...] | test.swift:573:16:573:23 | call to source() : | test.swift:578:13:578:32 | \\...[...] | result | +| test.swift:593:13:593:26 | \\...[...] | test.swift:590:16:590:23 | call to source() : | test.swift:593:13:593:26 | \\...[...] | result | diff --git a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected index 824622e770d..7b8717c8655 100644 --- a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected +++ b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected @@ -615,20 +615,50 @@ | test.swift:574:7:574:7 | f | test.swift:574:7:574:7 | SSA def(f) | | test.swift:574:11:574:14 | #keyPath(...) | test.swift:574:7:574:7 | f | | test.swift:574:11:574:14 | enter #keyPath(...) | test.swift:574:14:574:14 | KeyPathComponent | -| test.swift:579:7:579:7 | self | test.swift:579:7:579:7 | SSA def(self) | -| test.swift:581:3:581:3 | SSA def(self) | test.swift:582:5:582:5 | self | -| test.swift:581:3:581:3 | self | test.swift:581:3:581:3 | SSA def(self) | -| test.swift:581:8:581:11 | SSA def(s) | test.swift:582:14:582:14 | s | -| test.swift:581:8:581:11 | s | test.swift:581:8:581:11 | SSA def(s) | -| test.swift:582:5:582:5 | [post] self | test.swift:581:3:583:3 | self[return] | -| test.swift:582:5:582:5 | self | test.swift:581:3:583:3 | self[return] | -| test.swift:587:7:587:7 | SSA def(s) | test.swift:588:18:588:18 | s | -| test.swift:587:7:587:7 | s | test.swift:587:7:587:7 | SSA def(s) | -| test.swift:587:11:587:24 | call to S.init(x:) | test.swift:587:7:587:7 | s | -| test.swift:588:7:588:7 | SSA def(s2) | test.swift:590:13:590:13 | s2 | -| test.swift:588:7:588:7 | s2 | test.swift:588:7:588:7 | SSA def(s2) | -| test.swift:588:12:588:19 | call to S2.init(s:) | test.swift:588:7:588:7 | s2 | -| test.swift:589:7:589:7 | SSA def(f) | test.swift:590:25:590:25 | f | -| test.swift:589:7:589:7 | f | test.swift:589:7:589:7 | SSA def(f) | -| test.swift:589:11:589:17 | #keyPath(...) | test.swift:589:7:589:7 | f | -| test.swift:589:11:589:17 | enter #keyPath(...) | test.swift:589:15:589:15 | KeyPathComponent | +| test.swift:575:13:575:13 | s | test.swift:578:13:578:13 | s | +| test.swift:577:7:577:7 | SSA def(inferred) | test.swift:578:24:578:24 | inferred | +| test.swift:577:7:577:7 | inferred | test.swift:577:7:577:7 | SSA def(inferred) | +| test.swift:577:7:577:32 | ... as ... | test.swift:577:7:577:7 | inferred | +| test.swift:577:36:577:38 | #keyPath(...) | test.swift:577:7:577:32 | ... as ... | +| test.swift:577:36:577:38 | enter #keyPath(...) | test.swift:577:38:577:38 | KeyPathComponent | +| test.swift:582:7:582:7 | self | test.swift:582:7:582:7 | SSA def(self) | +| test.swift:584:3:584:3 | SSA def(self) | test.swift:585:5:585:5 | self | +| test.swift:584:3:584:3 | self | test.swift:584:3:584:3 | SSA def(self) | +| test.swift:584:8:584:11 | SSA def(s) | test.swift:585:14:585:14 | s | +| test.swift:584:8:584:11 | s | test.swift:584:8:584:11 | SSA def(s) | +| test.swift:585:5:585:5 | [post] self | test.swift:584:3:586:3 | self[return] | +| test.swift:585:5:585:5 | self | test.swift:584:3:586:3 | self[return] | +| test.swift:590:7:590:7 | SSA def(s) | test.swift:591:18:591:18 | s | +| test.swift:590:7:590:7 | s | test.swift:590:7:590:7 | SSA def(s) | +| test.swift:590:11:590:24 | call to S.init(x:) | test.swift:590:7:590:7 | s | +| test.swift:591:7:591:7 | SSA def(s2) | test.swift:593:13:593:13 | s2 | +| test.swift:591:7:591:7 | s2 | test.swift:591:7:591:7 | SSA def(s2) | +| test.swift:591:12:591:19 | call to S2.init(s:) | test.swift:591:7:591:7 | s2 | +| test.swift:592:7:592:7 | SSA def(f) | test.swift:593:25:593:25 | f | +| test.swift:592:7:592:7 | f | test.swift:592:7:592:7 | SSA def(f) | +| test.swift:592:11:592:17 | #keyPath(...) | test.swift:592:7:592:7 | f | +| test.swift:592:11:592:17 | enter #keyPath(...) | test.swift:592:15:592:15 | KeyPathComponent | +| test.swift:597:9:597:9 | SSA def(array) | test.swift:599:15:599:15 | array | +| test.swift:597:9:597:9 | array | test.swift:597:9:597:9 | SSA def(array) | +| test.swift:597:17:597:26 | [...] | test.swift:597:9:597:9 | array | +| test.swift:598:9:598:9 | SSA def(f) | test.swift:599:30:599:30 | f | +| test.swift:598:9:598:9 | f | test.swift:598:9:598:9 | SSA def(f) | +| test.swift:598:13:598:22 | #keyPath(...) | test.swift:598:9:598:9 | f | +| test.swift:598:13:598:22 | enter #keyPath(...) | test.swift:598:20:598:22 | KeyPathComponent | +| test.swift:603:7:603:7 | self | test.swift:603:7:603:7 | SSA def(self) | +| test.swift:605:3:605:3 | SSA def(self) | test.swift:606:5:606:5 | self | +| test.swift:605:3:605:3 | self | test.swift:605:3:605:3 | SSA def(self) | +| test.swift:605:8:605:12 | SSA def(s) | test.swift:606:14:606:14 | s | +| test.swift:605:8:605:12 | s | test.swift:605:8:605:12 | SSA def(s) | +| test.swift:606:5:606:5 | [post] self | test.swift:605:3:607:3 | self[return] | +| test.swift:606:5:606:5 | self | test.swift:605:3:607:3 | self[return] | +| test.swift:611:9:611:9 | SSA def(s) | test.swift:612:29:612:29 | s | +| test.swift:611:9:611:9 | s | test.swift:611:9:611:9 | SSA def(s) | +| test.swift:611:13:611:26 | call to S.init(x:) | test.swift:611:9:611:9 | s | +| test.swift:612:9:612:9 | SSA def(s2) | test.swift:614:15:614:15 | s2 | +| test.swift:612:9:612:9 | s2 | test.swift:612:9:612:9 | SSA def(s2) | +| test.swift:612:14:612:30 | call to S2_Optional.init(s:) | test.swift:612:9:612:9 | s2 | +| test.swift:613:9:613:9 | SSA def(f) | test.swift:614:27:614:27 | f | +| test.swift:613:9:613:9 | f | test.swift:613:9:613:9 | SSA def(f) | +| test.swift:613:13:613:29 | #keyPath(...) | test.swift:613:9:613:9 | f | +| test.swift:613:13:613:29 | enter #keyPath(...) | test.swift:613:26:613:26 | KeyPathComponent | diff --git a/swift/ql/test/library-tests/dataflow/dataflow/test.swift b/swift/ql/test/library-tests/dataflow/dataflow/test.swift index 51a549bde25..e3a74f920ef 100644 --- a/swift/ql/test/library-tests/dataflow/dataflow/test.swift +++ b/swift/ql/test/library-tests/dataflow/dataflow/test.swift @@ -573,6 +573,9 @@ func testKeyPath() { let s = S(x: source()) let f = \S.x sink(arg: s[keyPath: f]) // $ flow=573 + + let inferred : KeyPath = \.x + sink(arg: s[keyPath: inferred]) // $ flow=573 } struct S2 { @@ -587,5 +590,26 @@ func testNestedKeyPath() { let s = S(x: source()) let s2 = S2(s: s) let f = \S2.s.x - sink(arg: s2[keyPath: f]) // $ flow=587 + sink(arg: s2[keyPath: f]) // $ flow=590 +} + +func testArrayKeyPath() { + let array = [source()] + let f = \[Int].[0] + sink(arg: array[keyPath: f]) // $ MISSING: flow=597 +} + +struct S2_Optional { + let s: S? + + init(s: S?) { + self.s = s + } +} + +func testOptionalKeyPath() { + let s = S(x: source()) + let s2 = S2_Optional(s: s) + let f = \S2_Optional.s?.x + sink(opt: s2[keyPath: f]) // $ MISSING: flow=611 } \ No newline at end of file