diff --git a/swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowElements.qll b/swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowElements.qll index b5557c71e86..38d7a8c3e9a 100644 --- a/swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowElements.qll +++ b/swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowElements.qll @@ -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() } +} diff --git a/swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowGraphImpl.qll b/swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowGraphImpl.qll index 4db8afaca7a..4d7cbe90ad0 100644 --- a/swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowGraphImpl.qll +++ b/swift/ql/lib/codeql/swift/controlflow/internal/ControlFlowGraphImpl.qll @@ -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 { diff --git a/swift/ql/lib/codeql/swift/dataflow/Ssa.qll b/swift/ql/lib/codeql/swift/dataflow/Ssa.qll index 9053428d4b0..0f67b0faa5a 100644 --- a/swift/ql/lib/codeql/swift/dataflow/Ssa.qll +++ b/swift/ql/lib/codeql/swift/dataflow/Ssa.qll @@ -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(_) } + } } diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowDispatch.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowDispatch.qll index 0fe0acad457..d416f16b583 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowDispatch.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowDispatch.qll @@ -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() +} diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll index fc3321d2263..3de5e0dfdf9 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll @@ -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() } diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPublic.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPublic.qll index 70afd2651e1..67a184193d0 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPublic.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPublic.qll @@ -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. diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/SsaImplSpecific.qll b/swift/ql/lib/codeql/swift/dataflow/internal/SsaImplSpecific.qll index bd7373935aa..458e0b3a2e6 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/SsaImplSpecific.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/SsaImplSpecific.qll @@ -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 } diff --git a/swift/ql/lib/codeql/swift/elements/expr/Argument.qll b/swift/ql/lib/codeql/swift/elements/expr/Argument.qll index c2a25b877a4..88c11b14013 100644 --- a/swift/ql/lib/codeql/swift/elements/expr/Argument.qll +++ b/swift/ql/lib/codeql/swift/elements/expr/Argument.qll @@ -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 } } diff --git a/swift/ql/test/library-tests/controlflow/graph/Cfg.expected b/swift/ql/test/library-tests/controlflow/graph/Cfg.expected index 1a6485f84f6..6a45f334141 100644 --- a/swift/ql/test/library-tests/controlflow/graph/Cfg.expected +++ b/swift/ql/test/library-tests/controlflow/graph/Cfg.expected @@ -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) diff --git a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected new file mode 100644 index 00000000000..fe79e3ab862 --- /dev/null +++ b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected @@ -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 | diff --git a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.ql b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.ql new file mode 100644 index 00000000000..be4f604a4f7 --- /dev/null +++ b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.ql @@ -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 diff --git a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected index 92fe3d7565c..8c4f15886a1 100644 --- a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected +++ b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected @@ -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 | diff --git a/swift/ql/test/library-tests/dataflow/dataflow/test.swift b/swift/ql/test/library-tests/dataflow/dataflow/test.swift index d20fecb54d7..113db2dfea7 100644 --- a/swift/ql/test/library-tests/dataflow/dataflow/test.swift +++ b/swift/ql/test/library-tests/dataflow/dataflow/test.swift @@ -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) +} \ No newline at end of file