Merge pull request #9342 from rdmarsh2/rdmarsh2/swift/dataflow-global-flow

Swift: initial interprocedural data flow implementation
This commit is contained in:
Mathias Vorreiter Pedersen
2022-05-30 13:54:56 +01:00
committed by GitHub
13 changed files with 652 additions and 90 deletions

View File

@@ -3,6 +3,7 @@ private import swift
cached
newtype TControlFlowElement =
TAstElement(AstNode n) or
TFuncDeclElement(AbstractFunctionDecl func) { func.hasBody() } or
TPropertyGetterElement(Decl accessor, Expr ref) { isPropertyGetterElement(accessor, ref) } or
TPropertySetterElement(AccessorDecl accessor, AssignExpr assign) {
isPropertySetterElement(accessor, assign)
@@ -161,3 +162,13 @@ class PropertyObserverElement extends ControlFlowElement, TPropertyObserverEleme
AssignExpr getAssignExpr() { result = assign }
}
class FuncDeclElement extends ControlFlowElement, TFuncDeclElement {
AbstractFunctionDecl func;
FuncDeclElement() { this = TFuncDeclElement(func) }
override string toString() { result = func.toString() }
override Location getLocation() { result = func.getLocation() }
}

View File

@@ -48,15 +48,15 @@ module CfgScope {
private class BodyStmtCallableScope extends Range_ instanceof AbstractFunctionDecl {
final override predicate entry(ControlFlowElement first) {
exists(Stmts::BraceStmtTree tree |
tree.getAst() = super.getBody() and
tree.firstInner(first)
exists(Decls::FuncDeclTree tree |
tree.getAst() = this and
first = tree
)
}
final override predicate exit(ControlFlowElement last, Completion c) {
exists(Stmts::BraceStmtTree tree |
tree.getAst() = super.getBody() and
exists(Decls::FuncDeclTree tree |
tree.getAst() = this and
tree.last(last, c)
)
}
@@ -881,6 +881,21 @@ module Decls {
)
}
}
class FuncDeclTree extends StandardPreOrderTree, TFuncDeclElement {
AbstractFunctionDecl ast;
FuncDeclTree() { this = TFuncDeclElement(ast) }
AbstractFunctionDecl getAst() { result = ast }
final override ControlFlowElement getChildElement(int i) {
result.asAstNode() = ast.getParam(i)
or
result.asAstNode() = ast.getBody() and
i = ast.getNumberOfParams()
}
}
}
module Exprs {

View File

@@ -64,6 +64,29 @@ module Ssa {
a = bb.getNode(i).getNode().asAstNode() and
value.getNode().asAstNode() = a.getSource()
)
or
exists(VarDecl var, BasicBlock bb, int blockIndex, PatternBindingDecl pbd |
this.definesAt(var, bb, blockIndex) and
pbd.getAPattern() = bb.getNode(blockIndex).getNode().asAstNode() and
value.getNode().asAstNode() = var.getParentInitializer()
)
}
}
cached
class PhiDefinition extends Definition, SsaImplCommon::PhiNode {
cached
override Location getLocation() {
exists(BasicBlock bb, int i |
this.definesAt(_, bb, i) and
result = bb.getLocation()
)
}
cached
Definition getPhiInput(BasicBlock bb) { SsaImplCommon::phiHasInputFromBlock(this, result, bb) }
cached
Definition getAPhiInput() { result = this.getPhiInput(_) }
}
}

View File

@@ -1,5 +1,6 @@
private import swift
private import DataFlowPrivate
private import DataFlowPublic
newtype TReturnKind = TNormalReturnKind()
@@ -42,47 +43,34 @@ class DataFlowCallable extends TDataFlowCallable {
* A call. This includes calls from source code, as well as call(back)s
* inside library callables with a flow summary.
*/
class DataFlowCall extends TDataFlowCall {
class DataFlowCall extends ExprNode {
DataFlowCall() { this.asExpr() instanceof CallExpr }
/** Gets the enclosing callable. */
DataFlowCallable getEnclosingCallable() { none() }
/** Gets a textual representation of this call. */
string toString() { none() }
/** Gets the location of this call. */
Location getLocation() { none() }
/**
* Holds if this element is at the specified location.
* The location spans column `startcolumn` of line `startline` to
* column `endcolumn` of line `endline` in file `filepath`.
* For more information, see
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries).
*/
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
}
cached
private module Cached {
cached
newtype TDataFlowCallable = TODO_TDataFlowCallable()
cached
newtype TDataFlowCall = TODO_TDataFlowCall()
newtype TDataFlowCallable = TDataFlowFunc(FuncDecl func)
/** Gets a viable run-time target for the call `call`. */
cached
DataFlowCallable viableCallable(DataFlowCall call) { none() }
DataFlowCallable viableCallable(DataFlowCall call) {
result = TDataFlowFunc(call.asExpr().(CallExpr).getStaticTarget())
}
cached
newtype TArgumentPosition = TODO_TArgumentPosition()
newtype TArgumentPosition =
TThisArgument() or
// we rely on default exprs generated in the caller for ordering
TPositionalArgument(int n) { n = any(Argument arg).getIndex() }
cached
newtype TParameterPosition = TODO_TParameterPosition()
newtype TParameterPosition =
TThisParameter() or
TPositionalParameter(int n) { n = any(Argument arg).getIndex() }
}
import Cached
@@ -105,12 +93,25 @@ class ParameterPosition extends TParameterPosition {
string toString() { none() }
}
class PositionalParameterPosition extends ParameterPosition, TPositionalParameter {
int getIndex() { this = TPositionalParameter(result) }
}
/** An argument position. */
class ArgumentPosition extends TArgumentPosition {
/** Gets a textual representation of this position. */
string toString() { none() }
}
class PositionalArgumentPosition extends ArgumentPosition, TPositionalArgument {
int getIndex() { this = TPositionalArgument(result) }
}
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
pragma[inline]
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { none() }
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
ppos instanceof TThisParameter and
apos instanceof TThisArgument
or
ppos.(PositionalParameterPosition).getIndex() = apos.(PositionalArgumentPosition).getIndex()
}

View File

@@ -3,6 +3,8 @@ private import DataFlowPublic
private import DataFlowDispatch
private import codeql.swift.controlflow.CfgNodes
private import codeql.swift.dataflow.Ssa
private import codeql.swift.controlflow.BasicBlocks
private import codeql.swift.dataflow.internal.SsaImplCommon as SsaImpl
/** Gets the callable in which this node occurs. */
DataFlowCallable nodeGetEnclosingCallable(NodeImpl n) { result = n.getEnclosingCallable() }
@@ -31,12 +33,25 @@ private class ExprNodeImpl extends ExprNode, NodeImpl {
override Location getLocationImpl() { result = expr.getLocation() }
override string toStringImpl() { result = expr.toString() }
override DataFlowCallable getEnclosingCallable() { result = TDataFlowFunc(expr.getScope()) }
}
private class SsaDefinitionNodeImpl extends SsaDefinitionNode, NodeImpl {
override Location getLocationImpl() { result = def.getLocation() }
override string toStringImpl() { result = def.toString() }
override DataFlowCallable getEnclosingCallable() {
result = TDataFlowFunc(def.getBasicBlock().getScope())
}
}
private predicate localFlowSsaInput(Node nodeFrom, Ssa::Definition def, Ssa::Definition next) {
exists(BasicBlock bb, int i | SsaImpl::lastRefRedef(def, bb, i, next) |
def.definesAt(_, bb, i) and
def = nodeFrom.asDefinition()
)
}
/** A collection of cached types and predicates to be evaluated in the same stage. */
@@ -45,7 +60,6 @@ private module Cached {
cached
newtype TNode =
TExprNode(ExprCfgNode e) or
TNormalParameterNode(ParamDecl p) or
TSsaDefinitionNode(Ssa::Definition def)
private predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) {
@@ -60,6 +74,9 @@ private module Cached {
or
// use-use flow
def.adjacentReadPair(nodeFrom.getCfgNode(), nodeTo.getCfgNode())
or
// step from previous read to Phi node
localFlowSsaInput(nodeFrom, def, nodeTo.asDefinition())
)
}
@@ -93,18 +110,29 @@ private module ParameterNodes {
predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { none() }
}
class NormalParameterNode extends ParameterNodeImpl, TNormalParameterNode {
class NormalParameterNode extends ParameterNodeImpl, SsaDefinitionNode {
ParamDecl param;
NormalParameterNode() { this = TNormalParameterNode(param) }
NormalParameterNode() {
exists(BasicBlock bb, int i |
super.asDefinition().definesAt(param, bb, i) and
bb.getNode(i).getNode().asAstNode() = param
)
}
override Location getLocationImpl() { result = param.getLocation() }
override string toStringImpl() { result = param.toString() }
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
none() // TODO
exists(FuncDecl f, int index |
c = TDataFlowFunc(f) and
f.getParam(index) = param and
pos = TPositionalParameter(index)
)
}
override DataFlowCallable getEnclosingCallable() { isParameterOf(result, _) }
}
}
@@ -119,7 +147,16 @@ abstract class ArgumentNode extends Node {
final DataFlowCall getCall() { this.argumentOf(result, _) }
}
private module ArgumentNodes { }
private module ArgumentNodes {
class NormalArgumentNode extends ExprNode, ArgumentNode {
NormalArgumentNode() { exists(CallExpr call | call.getAnArgument().getExpr() = this.asExpr()) }
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
call.asExpr().(CallExpr).getArgument(pos.(PositionalArgumentPosition).getIndex()).getExpr() =
this.asExpr()
}
}
}
import ArgumentNodes
@@ -129,7 +166,13 @@ abstract class ReturnNode extends Node {
abstract ReturnKind getKind();
}
private module ReturnNodes { }
private module ReturnNodes {
class ReturnReturnNode extends ReturnNode, ExprNode {
ReturnReturnNode() { exists(ReturnStmt stmt | stmt.getResult() = this.asExpr()) }
override ReturnKind getKind() { result instanceof NormalReturnKind }
}
}
import ReturnNodes
@@ -139,7 +182,13 @@ abstract class OutNode extends Node {
abstract DataFlowCall getCall(ReturnKind kind);
}
private module OutNodes { }
private module OutNodes {
class CallOutNode extends OutNode, DataFlowCall {
override DataFlowCall getCall(ReturnKind kind) {
result = this and kind instanceof NormalReturnKind
}
}
}
import OutNodes
@@ -169,7 +218,9 @@ class DataFlowType extends TDataFlowType {
}
/** Gets the type of `n` used for type pruning. */
DataFlowType getNodeType(NodeImpl n) { none() }
DataFlowType getNodeType(NodeImpl n) {
any() // return the singleton DataFlowType until we support type pruning for Swift
}
/** Gets a string representation of a `DataFlowType`. */
string ppReprType(DataFlowType t) { result = t.toString() }

View File

@@ -69,7 +69,7 @@ class ExprNode extends Node, TExprNode {
* The value of a parameter at function entry, viewed as a node in a data
* flow graph.
*/
class ParameterNode extends Node, TNormalParameterNode instanceof ParameterNodeImpl { }
class ParameterNode extends Node, SsaDefinitionNode instanceof ParameterNodeImpl { }
/**
*/
@@ -98,7 +98,7 @@ class PostUpdateNode extends Node instanceof PostUpdateNodeImpl {
}
/** Gets a node corresponding to expression `e`. */
ExprNode exprNode(DataFlowExpr e) { none() }
ExprNode exprNode(DataFlowExpr e) { result.asExpr() = e }
/**
* Gets the node corresponding to the value of parameter `p` at function entry.

View File

@@ -27,6 +27,10 @@ predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain)
v.getParentPattern() = pattern and
certain = true
)
or
v instanceof ParamDecl and
bb.getNode(i).getNode().asAstNode() = v and
certain = true
}
private predicate isLValue(DeclRefExpr ref) { any(AssignExpr assign).getDest() = ref }

View File

@@ -1,5 +1,8 @@
private import codeql.swift.generated.expr.Argument
private import codeql.swift.elements.expr.ApplyExpr
class Argument extends ArgumentBase {
override string toString() { result = this.getLabel() + ": " + this.getExpr().toString() }
int getIndex() { any(ApplyExpr apply).getArgument(result) = this }
}

View File

@@ -1,12 +1,15 @@
cfg.swift:
# 5| enter returnZero
#-----| -> 0
#-----| -> returnZero
# 5| exit returnZero
# 5| exit returnZero (normal)
#-----| -> exit returnZero
# 5| returnZero
#-----| -> 0
# 5| return ...
#-----| return -> exit returnZero (normal)
@@ -14,13 +17,19 @@ cfg.swift:
#-----| -> return ...
# 15| enter isZero
#-----| -> ==
#-----| -> isZero
# 15| exit isZero
# 15| exit isZero (normal)
#-----| -> exit isZero
# 15| isZero
#-----| -> x
# 15| x
#-----| -> ==
# 15| return ...
#-----| return -> exit isZero (normal)
@@ -44,13 +53,19 @@ cfg.swift:
#-----| -> ... call to == ...
# 17| enter mightThrow
#-----| -> guard ... else { ... }
#-----| -> mightThrow
# 17| exit mightThrow
# 17| exit mightThrow (normal)
#-----| -> exit mightThrow
# 17| mightThrow
#-----| -> x
# 17| x
#-----| -> guard ... else { ... }
# 18| guard ... else { ... }
#-----| -> >=
@@ -164,13 +179,19 @@ cfg.swift:
#-----| -> ... call to + ...
# 26| enter tryCatch
#-----| -> do { ... } catch { ... }
#-----| -> tryCatch
# 26| exit tryCatch
# 26| exit tryCatch (normal)
#-----| -> exit tryCatch
# 26| tryCatch
#-----| -> x
# 26| x
#-----| -> do { ... } catch { ... }
# 27| do { ... } catch { ... }
#-----| -> mightThrow
@@ -363,28 +384,48 @@ cfg.swift:
# 42| 0
#-----| -> return ...
# 45| createClosure1
#-----| -> s
# 45| enter createClosure1
#-----| -> { ... }
#-----| -> createClosure1
# 45| exit createClosure1
# 45| exit createClosure1 (normal)
#-----| -> exit createClosure1
# 45| s
#-----| -> { ... }
# 46| return ...
#-----| return -> exit createClosure1 (normal)
# 46| { ... }
#-----| -> return ...
# 51| createClosure2
#-----| -> x
# 51| enter createClosure2
#-----| -> createClosure2
# 51| x
# 52| enter f
#-----| -> +
#-----| -> f
# 52| exit f
# 52| exit f (normal)
#-----| -> exit f
# 52| f
#-----| -> y
# 52| y
#-----| -> +
# 53| return ...
#-----| return -> exit f (normal)
@@ -407,23 +448,32 @@ cfg.swift:
# 53| y
#-----| -> ... call to + ...
# 58| createClosure3
#-----| -> x
# 58| enter createClosure3
#-----| -> { ... }
#-----| -> createClosure3
# 58| exit createClosure3
# 58| exit createClosure3 (normal)
#-----| -> exit createClosure3
# 58| x
#-----| -> { ... }
# 59| return ...
#-----| return -> exit createClosure3 (normal)
# 59| { ... }
#-----| -> return ...
# 64| enter callClosures
# 64| callClosures
#-----| -> x1
# 64| enter callClosures
#-----| -> callClosures
# 64| exit callClosures
# 64| exit callClosures (normal)
@@ -502,13 +552,19 @@ cfg.swift:
#-----| -> call to ...
# 70| enter maybeParseInt
#-----| -> n
#-----| -> maybeParseInt
# 70| exit maybeParseInt
# 70| exit maybeParseInt (normal)
#-----| -> exit maybeParseInt
# 70| maybeParseInt
#-----| -> s
# 70| s
#-----| -> n
# 71| var ... = ...
#-----| -> n
@@ -546,13 +602,16 @@ cfg.swift:
#-----| -> (Int?) ...
# 75| enter forceAndBackToOptional
#-----| -> nBang
#-----| -> forceAndBackToOptional
# 75| exit forceAndBackToOptional
# 75| exit forceAndBackToOptional (normal)
#-----| -> exit forceAndBackToOptional
# 75| forceAndBackToOptional
#-----| -> nBang
# 76| var ... = ...
#-----| -> nBang
@@ -629,6 +688,9 @@ cfg.swift:
#-----| -> ... call to + ...
# 81| enter testInOut
#-----| -> testInOut
# 81| testInOut
#-----| -> temp
# 82| var ... = ...
@@ -642,14 +704,20 @@ cfg.swift:
# 82| 10
#-----| -> var ... = ...
# 84| enter add
# 84| add
#-----| -> a
# 84| enter add
#-----| -> add
# 84| exit add
# 84| exit add (normal)
#-----| -> exit add
# 84| a
#-----| -> a
# 85| a
#-----| -> +
@@ -678,14 +746,20 @@ cfg.swift:
# 85| 1
#-----| -> ... call to + ...
# 88| enter addOptional
# 88| addOptional
#-----| -> a
# 88| enter addOptional
#-----| -> addOptional
# 88| exit addOptional
# 88| exit addOptional (normal)
#-----| -> exit addOptional
# 88| a
#-----| -> a
# 89| a
#-----| -> nil
@@ -695,21 +769,44 @@ cfg.swift:
# 89| nil
#-----| -> ... = ...
# 98| enter init
#-----| -> init
# 98| exit init
# 98| exit init (normal)
#-----| -> exit init
# 98| init
#-----| -> { ... }
# 98| { ... }
#-----| -> exit init (normal)
# 99| enter get
#-----| -> get
# 99| exit get
# 99| exit get (normal)
#-----| -> exit get
# 99| get
# 100| deinit
#-----| -> n
# 100| enter deinit
#-----| -> self
#-----| -> deinit
# 100| exit deinit
# 100| exit deinit (normal)
#-----| -> exit deinit
# 100| n
#-----| -> self
# 101| .myInt
#-----| -> n
@@ -726,13 +823,16 @@ cfg.swift:
#-----| return -> exit deinit (normal)
# 104| enter getMyInt
#-----| -> self
#-----| -> getMyInt
# 104| exit getMyInt
# 104| exit getMyInt (normal)
#-----| -> exit getMyInt
# 104| getMyInt
#-----| -> self
# 105| return ...
#-----| return -> exit getMyInt (normal)
@@ -743,13 +843,25 @@ cfg.swift:
#-----| -> getter for .myInt
# 109| enter testMemberRef
#-----| -> c
#-----| -> testMemberRef
# 109| exit testMemberRef
# 109| exit testMemberRef (normal)
#-----| -> exit testMemberRef
# 109| testMemberRef
#-----| -> param
# 109| param
#-----| -> inoutParam
# 109| inoutParam
#-----| -> opt
# 109| opt
#-----| -> c
# 110| var ... = ...
#-----| -> c
@@ -1233,13 +1345,19 @@ cfg.swift:
#-----| -> TBD (DotSelfExpr)
# 137| enter patterns
#-----| -> ...
#-----| -> patterns
# 137| exit patterns
# 137| exit patterns (normal)
#-----| -> exit patterns
# 137| patterns
#-----| -> x
# 137| x
#-----| -> ...
# 138| for ... in ... { ... }
#-----| non-empty -> _
#-----| empty -> switch x { ... }
@@ -1336,13 +1454,19 @@ cfg.swift:
#-----| -> return ...
# 163| enter testDefer
#-----| -> defer { ... }
#-----| -> testDefer
# 163| exit testDefer
# 163| exit testDefer (normal)
#-----| -> exit testDefer
# 163| testDefer
#-----| -> x
# 163| x
#-----| -> defer { ... }
# 165| defer { ... }
#-----| -> defer { ... }
@@ -1468,13 +1592,19 @@ cfg.swift:
#-----| -> [...]
# 181| enter m1
#-----| -> if ... then { ... } else { ... }
#-----| -> m1
# 181| exit m1
# 181| exit m1 (normal)
#-----| -> exit m1
# 181| m1
#-----| -> x
# 181| x
#-----| -> if ... then { ... } else { ... }
# 182| if ... then { ... } else { ... }
#-----| -> >
@@ -1679,13 +1809,19 @@ cfg.swift:
#-----| -> [...]
# 193| enter m2
#-----| -> if ... then { ... }
#-----| -> m2
# 193| exit m2
# 193| exit m2 (normal)
#-----| -> exit m2
# 193| m2
#-----| -> b
# 193| b
#-----| -> if ... then { ... }
# 194| if ... then { ... }
#-----| -> b
@@ -1709,13 +1845,19 @@ cfg.swift:
#-----| -> return ...
# 200| enter m3
#-----| -> if ... then { ... }
#-----| -> m3
# 200| exit m3
# 200| exit m3 (normal)
#-----| -> exit m3
# 200| m3
#-----| -> x
# 200| x
#-----| -> if ... then { ... }
# 201| if ... then { ... }
#-----| -> <
@@ -1837,13 +1979,25 @@ cfg.swift:
#-----| -> (Int) ...
# 210| enter m4
#-----| -> b1
#-----| -> m4
# 210| exit m4
# 210| exit m4 (normal)
#-----| -> exit m4
# 210| m4
#-----| -> b1
# 210| b1
#-----| -> b2
# 210| b2
#-----| -> b3
# 210| b3
#-----| -> b1
# 211| return ...
#-----| return -> exit m4 (normal)
@@ -1880,14 +2034,20 @@ cfg.swift:
# 211| !b2 || !b3
#-----| -> ... ? ... : ...
# 214| conversionsInSplitEntry
#-----| -> b
# 214| enter conversionsInSplitEntry
#-----| -> if ... then { ... } else { ... }
#-----| -> conversionsInSplitEntry
# 214| exit conversionsInSplitEntry
# 214| exit conversionsInSplitEntry (normal)
#-----| -> exit conversionsInSplitEntry
# 214| b
#-----| -> if ... then { ... } else { ... }
# 215| if ... then { ... } else { ... }
#-----| -> b
@@ -1926,9 +2086,12 @@ cfg.swift:
# 219| !b
#-----| -> return ...
# 223| enter constant_condition
# 223| constant_condition
#-----| -> if ... then { ... }
# 223| enter constant_condition
#-----| -> constant_condition
# 223| exit constant_condition
# 223| exit constant_condition (normal)
@@ -1975,14 +2138,20 @@ cfg.swift:
# 225| [...]
#-----| -> [...]
# 229| empty_else
#-----| -> b
# 229| enter empty_else
#-----| -> if ... then { ... } else { ... }
#-----| -> empty_else
# 229| exit empty_else
# 229| exit empty_else (normal)
#-----| -> exit empty_else
# 229| b
#-----| -> if ... then { ... } else { ... }
# 230| if ... then { ... } else { ... }
#-----| -> b
@@ -2053,14 +2222,23 @@ cfg.swift:
#-----| -> (Any) ...
#-----| -> (TBD (ProtocolCompositionType)) ...
# 237| disjunct
#-----| -> b1
# 237| enter disjunct
#-----| -> if ... then { ... }
#-----| -> disjunct
# 237| exit disjunct
# 237| exit disjunct (normal)
#-----| -> exit disjunct
# 237| b1
#-----| -> b2
# 237| b2
#-----| -> if ... then { ... }
# 238| if ... then { ... }
#-----| -> b1
@@ -2115,14 +2293,23 @@ cfg.swift:
#-----| -> (Any) ...
#-----| -> (TBD (ProtocolCompositionType)) ...
# 243| binaryExprs
#-----| -> a
# 243| enter binaryExprs
#-----| -> c
#-----| -> binaryExprs
# 243| exit binaryExprs
# 243| exit binaryExprs (normal)
#-----| -> exit binaryExprs
# 243| a
#-----| -> b
# 243| b
#-----| -> c
# 244| var ... = ...
#-----| -> c
@@ -2572,13 +2759,22 @@ cfg.swift:
#-----| -> ... call to >= ...
# 262| enter interpolatedString
#-----| -> "..."
#-----| -> interpolatedString
# 262| exit interpolatedString
# 262| exit interpolatedString (normal)
#-----| -> exit interpolatedString
# 262| interpolatedString
#-----| -> x
# 262| x
#-----| -> y
# 262| y
#-----| -> "..."
# 263| return ...
#-----| return -> exit interpolatedString (normal)
@@ -2586,13 +2782,16 @@ cfg.swift:
#-----| -> return ...
# 266| enter testSubscriptExpr
#-----| -> a
#-----| -> testSubscriptExpr
# 266| exit testSubscriptExpr
# 266| exit testSubscriptExpr (normal)
#-----| -> exit testSubscriptExpr
# 266| testSubscriptExpr
#-----| -> a
# 267| var ... = ...
#-----| -> a
@@ -3783,13 +3982,19 @@ cfg.swift:
#-----| -> getter for ...[...]
# 299| enter loop1
#-----| -> while ... { ... }
#-----| -> loop1
# 299| exit loop1
# 299| exit loop1 (normal)
#-----| -> exit loop1
# 299| loop1
#-----| -> x
# 299| x
#-----| -> while ... { ... }
# 300| while ... { ... }
#-----| -> >=
@@ -3874,13 +4079,19 @@ cfg.swift:
#-----| -> ... call to -= ...
# 306| enter loop2
#-----| -> while ... { ... }
#-----| -> loop2
# 306| exit loop2
# 306| exit loop2 (normal)
#-----| -> exit loop2
# 306| loop2
#-----| -> x
# 306| x
#-----| -> while ... { ... }
# 307| while ... { ... }
#-----| -> >=
@@ -4086,13 +4297,19 @@ cfg.swift:
#-----| -> [...]
# 321| enter labeledLoop
#-----| -> while ... { ... }
#-----| -> labeledLoop
# 321| exit labeledLoop
# 321| exit labeledLoop (normal)
#-----| -> exit labeledLoop
# 321| labeledLoop
#-----| -> x
# 321| x
#-----| -> while ... { ... }
# 322| while ... { ... }
#-----| -> >=
@@ -4328,13 +4545,19 @@ cfg.swift:
#-----| -> [...]
# 338| enter testRepeat
#-----| -> repeat { ... } while ...
#-----| -> testRepeat
# 338| exit testRepeat
# 338| exit testRepeat (normal)
#-----| -> exit testRepeat
# 338| testRepeat
#-----| -> x
# 338| x
#-----| -> repeat { ... } while ...
# 339| repeat { ... } while ...
#-----| -> print
@@ -4416,13 +4639,16 @@ cfg.swift:
#-----| -> ... call to >= ...
# 345| enter loop_with_identity_expr
#-----| -> x
#-----| -> loop_with_identity_expr
# 345| exit loop_with_identity_expr
# 345| exit loop_with_identity_expr (normal)
#-----| -> exit loop_with_identity_expr
# 345| loop_with_identity_expr
#-----| -> x
# 346| var ... = ...
#-----| -> x
@@ -4489,21 +4715,44 @@ cfg.swift:
# 348| 1
#-----| -> ... call to += ...
# 352| enter init
#-----| -> init
# 352| exit init
# 352| exit init (normal)
#-----| -> exit init
# 352| init
#-----| -> { ... }
# 352| { ... }
#-----| -> exit init (normal)
# 353| enter get
#-----| -> get
# 353| exit get
# 353| exit get (normal)
#-----| -> exit get
# 353| get
# 354| deinit
#-----| -> arg
# 354| enter deinit
#-----| -> self
#-----| -> deinit
# 354| exit deinit
# 354| exit deinit (normal)
#-----| -> exit deinit
# 354| arg
#-----| -> self
# 355| .c
#-----| -> arg
@@ -4520,13 +4769,16 @@ cfg.swift:
#-----| return -> exit deinit (normal)
# 358| enter getOptional
#-----| -> self
#-----| -> getOptional
# 358| exit getOptional
# 358| exit getOptional (normal)
#-----| -> exit getOptional
# 358| getOptional
#-----| -> self
# 359| return ...
#-----| return -> exit getOptional (normal)
@@ -4537,13 +4789,19 @@ cfg.swift:
#-----| -> getter for .c
# 363| enter testOptional
#-----| -> getMyInt
#-----| -> testOptional
# 363| exit testOptional
# 363| exit testOptional (normal)
#-----| -> exit testOptional
# 363| testOptional
#-----| -> c
# 363| c
#-----| -> getMyInt
# 364| return ...
#-----| return -> exit testOptional (normal)
@@ -4583,13 +4841,22 @@ cfg.swift:
#-----| -> getOptional
# 367| enter testCapture
#-----| -> z
#-----| -> testCapture
# 367| exit testCapture
# 367| exit testCapture (normal)
#-----| -> exit testCapture
# 367| testCapture
#-----| -> x
# 367| x
#-----| -> y
# 367| y
#-----| -> z
# 368| return ...
#-----| return -> exit testCapture (normal)
@@ -4634,13 +4901,19 @@ cfg.swift:
#-----| -> var ... = ...
# 373| enter testTupleElement
#-----| -> +
#-----| -> testTupleElement
# 373| exit testTupleElement
# 373| exit testTupleElement (normal)
#-----| -> exit testTupleElement
# 373| testTupleElement
#-----| -> t
# 373| t
#-----| -> +
# 374| return ...
#-----| return -> exit testTupleElement (normal)
@@ -4737,18 +5010,37 @@ cfg.swift:
# 377| cfg.Derived
#-----| -> #...
# 377| enter init
#-----| -> init
# 377| exit init
# 377| exit init (normal)
#-----| -> exit init
# 377| init
#-----| -> { ... }
# 377| { ... }
#-----| -> exit init (normal)
# 377| deinit
# 377| enter deinit
#-----| -> _unimplementedInitializer
#-----| -> deinit
# 377| exit deinit
# 377| exit deinit (normal)
#-----| -> exit deinit
# 378| enter deinit
# 378| deinit
#-----| -> call to ...
#-----| -> TBD (OtherConstructorDeclRefExpr)
# 378| enter deinit
#-----| -> deinit
# 378| exit deinit
# 378| exit deinit (normal)
@@ -4778,14 +5070,20 @@ cfg.swift:
# 380| return
#-----| return -> exit deinit (normal)
# 383| doWithoutCatch
#-----| -> x
# 383| enter doWithoutCatch
#-----| -> do { ... }
#-----| -> doWithoutCatch
# 383| exit doWithoutCatch
# 383| exit doWithoutCatch (normal)
#-----| -> exit doWithoutCatch
# 383| x
#-----| -> do { ... }
# 384| do { ... }
#-----| -> mightThrow
@@ -4830,13 +5128,18 @@ cfg.swift:
# 386| [...]
#-----| -> [...]
# 394| enter (unnamed function decl)
# 394| (unnamed function decl)
#-----| -> yield ...
#-----| -> TBD (YieldStmt)
# 394| enter (unnamed function decl)
#-----| -> (unnamed function decl)
# 394| enter get
#-----| -> get
# 394| enter set
#-----| -> set
# 394| exit (unnamed function decl)
@@ -4853,15 +5156,25 @@ cfg.swift:
# 394| exit set (normal)
#-----| -> exit set
# 394| get
# 394| set
#-----| -> value
# 394| value
# 394| yield ...
#-----| -> exit (unnamed function decl) (normal)
# 394| TBD (YieldStmt)
#-----| -> exit (unnamed function decl) (normal)
# 395| enter deinit
# 395| deinit
#-----| -> self
# 395| enter deinit
#-----| -> deinit
# 395| exit deinit
# 395| exit deinit (normal)
@@ -4883,13 +5196,16 @@ cfg.swift:
#-----| return -> exit deinit (normal)
# 399| enter init
#-----| -> self
#-----| -> init
# 399| exit init
# 399| exit init (normal)
#-----| -> exit init
# 399| init
#-----| -> self
# 400| .field
#-----| -> 0
@@ -4902,14 +5218,23 @@ cfg.swift:
# 400| 0
#-----| -> ... = ...
# 404| enter dictionaryLiteral
# 404| dictionaryLiteral
#-----| -> x
# 404| enter dictionaryLiteral
#-----| -> dictionaryLiteral
# 404| exit dictionaryLiteral
# 404| exit dictionaryLiteral (normal)
#-----| -> exit dictionaryLiteral
# 404| x
#-----| -> y
# 404| y
#-----| -> x
# 405| return ...
#-----| return -> exit dictionaryLiteral (normal)

View File

@@ -0,0 +1,44 @@
edges
| test.swift:6:19:6:26 | call to source : | test.swift:7:15:7:15 | t1 |
| test.swift:6:19:6:26 | call to source : | test.swift:9:15:9:15 | t1 |
| test.swift:6:19:6:26 | call to source : | test.swift:10:15:10:15 | t2 |
| test.swift:25:20:25:27 | call to source : | test.swift:29:18:29:21 | WriteDef : |
| test.swift:25:20:25:27 | call to source : | test.swift:29:18:29:21 | x : |
| test.swift:26:26:26:33 | call to source : | test.swift:29:26:29:29 | WriteDef : |
| test.swift:26:26:26:33 | call to source : | test.swift:29:26:29:29 | y : |
| test.swift:29:18:29:21 | WriteDef : | test.swift:30:15:30:15 | x |
| test.swift:29:18:29:21 | x : | test.swift:30:15:30:15 | x |
| test.swift:29:26:29:29 | WriteDef : | test.swift:31:15:31:15 | y |
| test.swift:29:26:29:29 | y : | test.swift:31:15:31:15 | y |
| test.swift:35:12:35:19 | call to source : | test.swift:39:15:39:29 | call to callee_source |
| test.swift:43:19:43:26 | call to source : | test.swift:50:15:50:15 | t |
nodes
| test.swift:6:19:6:26 | call to source : | semmle.label | call to source : |
| test.swift:7:15:7:15 | t1 | semmle.label | t1 |
| test.swift:9:15:9:15 | t1 | semmle.label | t1 |
| test.swift:10:15:10:15 | t2 | semmle.label | t2 |
| test.swift:25:20:25:27 | call to source : | semmle.label | call to source : |
| test.swift:26:26:26:33 | call to source : | semmle.label | call to source : |
| test.swift:29:18:29:21 | WriteDef : | semmle.label | WriteDef : |
| test.swift:29:18:29:21 | WriteDef : | semmle.label | x : |
| test.swift:29:18:29:21 | x : | semmle.label | WriteDef : |
| test.swift:29:18:29:21 | x : | semmle.label | x : |
| test.swift:29:26:29:29 | WriteDef : | semmle.label | WriteDef : |
| test.swift:29:26:29:29 | WriteDef : | semmle.label | y : |
| test.swift:29:26:29:29 | y : | semmle.label | WriteDef : |
| test.swift:29:26:29:29 | y : | semmle.label | y : |
| test.swift:30:15:30:15 | x | semmle.label | x |
| test.swift:31:15:31:15 | y | semmle.label | y |
| test.swift:35:12:35:19 | call to source : | semmle.label | call to source : |
| test.swift:39:15:39:29 | call to callee_source | semmle.label | call to callee_source |
| test.swift:43:19:43:26 | call to source : | semmle.label | call to source : |
| test.swift:50:15:50:15 | t | semmle.label | t |
subpaths
#select
| test.swift:6:19:6:26 | call to source : | test.swift:7:15:7:15 | t1 |
| test.swift:6:19:6:26 | call to source : | test.swift:9:15:9:15 | t1 |
| test.swift:6:19:6:26 | call to source : | test.swift:10:15:10:15 | t2 |
| test.swift:25:20:25:27 | call to source : | test.swift:30:15:30:15 | x |
| test.swift:26:26:26:33 | call to source : | test.swift:31:15:31:15 | y |
| test.swift:35:12:35:19 | call to source : | test.swift:39:15:39:29 | call to callee_source |
| test.swift:43:19:43:26 | call to source : | test.swift:50:15:50:15 | t |

View File

@@ -0,0 +1,24 @@
import swift
import codeql.swift.dataflow.DataFlow
import DataFlow::PathGraph
class TestConfiguration extends DataFlow::Configuration {
TestConfiguration() { this = "TestConfiguration" }
override predicate isSource(DataFlow::Node src) {
src.asExpr().(CallExpr).getStaticTarget().getName() = "source"
}
override predicate isSink(DataFlow::Node sink) {
exists(CallExpr sinkCall |
sinkCall.getStaticTarget().getName() = "sink" and
sinkCall.getAnArgument().getExpr() = sink.asExpr()
)
}
override int explorationLimit() { result = 100 }
}
from DataFlow::PathNode src, DataFlow::PathNode sink, TestConfiguration test
where test.hasFlowPath(src, sink)
select src, sink

View File

@@ -1,6 +1,5 @@
| file://:0:0:0:0 | Phi | test.swift:15:15:15:15 | t2 |
| file://:0:0:0:0 | Phi | test.swift:21:15:21:15 | t1 |
| test.swift:6:9:6:13 | WriteDef | test.swift:7:15:7:15 | t1 |
| test.swift:6:19:6:26 | call to source | test.swift:6:9:6:13 | WriteDef |
| test.swift:7:15:7:15 | t1 | test.swift:8:10:8:10 | t1 |
| test.swift:8:5:8:10 | WriteDef | test.swift:10:15:10:15 | t2 |
| test.swift:8:10:8:10 | t1 | test.swift:8:5:8:10 | WriteDef |
@@ -8,7 +7,29 @@
| test.swift:9:15:9:15 | t1 | test.swift:11:8:11:8 | t1 |
| test.swift:12:9:12:14 | WriteDef | test.swift:13:19:13:19 | t2 |
| test.swift:12:14:12:14 | 0 | test.swift:12:9:12:14 | WriteDef |
| test.swift:15:5:15:5 | Phi | test.swift:15:15:15:15 | t2 |
| test.swift:15:15:15:15 | t2 | test.swift:19:14:19:14 | t2 |
| test.swift:17:5:17:10 | WriteDef | test.swift:18:11:18:11 | Phi |
| test.swift:17:10:17:10 | 0 | test.swift:17:5:17:10 | WriteDef |
| test.swift:18:11:18:11 | Phi | test.swift:19:9:19:14 | WriteDef |
| test.swift:18:11:18:11 | Phi | test.swift:21:15:21:15 | t1 |
| test.swift:19:9:19:14 | WriteDef | test.swift:18:11:18:11 | Phi |
| test.swift:19:14:19:14 | t2 | test.swift:19:9:19:14 | WriteDef |
| test.swift:19:14:19:14 | t2 | test.swift:19:14:19:14 | t2 |
| test.swift:29:18:29:21 | WriteDef | test.swift:30:15:30:15 | x |
| test.swift:29:18:29:21 | x | test.swift:30:15:30:15 | x |
| test.swift:29:26:29:29 | WriteDef | test.swift:31:15:31:15 | y |
| test.swift:29:26:29:29 | y | test.swift:31:15:31:15 | y |
| test.swift:42:16:42:19 | WriteDef | test.swift:45:8:45:8 | b |
| test.swift:42:16:42:19 | b | test.swift:45:8:45:8 | b |
| test.swift:43:9:43:13 | WriteDef | test.swift:46:13:46:13 | t1 |
| test.swift:43:19:43:26 | call to source | test.swift:43:9:43:13 | WriteDef |
| test.swift:46:9:46:13 | WriteDef | test.swift:50:5:50:5 | Phi |
| test.swift:46:13:46:13 | t1 | test.swift:46:9:46:13 | WriteDef |
| test.swift:48:9:48:13 | WriteDef | test.swift:50:5:50:5 | Phi |
| test.swift:48:13:48:13 | 1 | test.swift:48:9:48:13 | WriteDef |
| test.swift:50:5:50:5 | Phi | test.swift:50:15:50:15 | t |
| test.swift:58:9:58:12 | WriteDef | test.swift:59:15:59:15 | x |
| test.swift:58:18:58:18 | 0 | test.swift:58:9:58:12 | WriteDef |
| test.swift:59:15:59:15 | x | test.swift:60:23:60:23 | x |
| test.swift:60:23:60:23 | x | test.swift:61:15:61:15 | x |

View File

@@ -20,3 +20,43 @@ func intraprocedural_with_local_flow() -> Void {
}
sink(arg: t1)
}
func caller_source() -> Void {
callee_sink(x: source(), y: 1)
callee_sink(x: 1, y: source())
}
func callee_sink(x: Int, y: Int) -> Void {
sink(arg: x)
sink(arg: y)
}
func callee_source() -> Int {
return source()
}
func caller_sink() -> Void {
sink(arg: callee_source())
}
func branching(b: Bool) -> Void {
var t1: Int = source()
var t: Int = 0
if(b) {
t = t1;
} else {
t = 1;
}
sink(arg: t)
}
func inoutSource(arg: inout Int) -> Void {
arg = source()
}
func inoutUser() {
var x: Int = 0
sink(arg: x)
inoutSource(arg: &x)
sink(arg: x)
}