@@ -10,6 +10,7 @@ private import codeql.swift.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
1010private import codeql.swift.frameworks.StandardLibrary.PointerTypes
1111private import codeql.swift.frameworks.StandardLibrary.Array
1212private import codeql.swift.frameworks.StandardLibrary.Dictionary
13+ private import codeql.dataflow.VariableCapture as VariableCapture
1314
1415/** Gets the callable in which this node occurs. */
1516DataFlowCallable nodeGetEnclosingCallable ( Node n ) { result = n .( NodeImpl ) .getEnclosingCallable ( ) }
@@ -98,6 +99,16 @@ private class SsaDefinitionNodeImpl extends SsaDefinitionNode, NodeImpl {
9899 }
99100}
100101
102+ private class CaptureNodeImpl extends CaptureNode , NodeImpl {
103+ override Location getLocationImpl ( ) { result = this .getSynthesizedCaptureNode ( ) .getLocation ( ) }
104+
105+ override string toStringImpl ( ) { result = this .getSynthesizedCaptureNode ( ) .toString ( ) }
106+
107+ override DataFlowCallable getEnclosingCallable ( ) {
108+ result .asSourceCallable ( ) = this .getSynthesizedCaptureNode ( ) .getEnclosingCallable ( )
109+ }
110+ }
111+
101112private predicate localFlowSsaInput ( Node nodeFrom , Ssa:: Definition def , Ssa:: Definition next ) {
102113 exists ( BasicBlock bb , int i | def .lastRefRedef ( bb , i , next ) |
103114 def .definesAt ( _, bb , i ) and
@@ -145,7 +156,8 @@ private module Cached {
145156 } or
146157 TDictionarySubscriptNode ( SubscriptExpr e ) {
147158 e .getBase ( ) .getType ( ) .getCanonicalType ( ) instanceof CanonicalDictionaryType
148- }
159+ } or
160+ TCaptureNode ( CaptureFlow:: SynthesizedCaptureNode cn )
149161
150162 private predicate localSsaFlowStepUseUse ( Ssa:: Definition def , Node nodeFrom , Node nodeTo ) {
151163 def .adjacentReadPair ( nodeFrom .getCfgNode ( ) , nodeTo .getCfgNode ( ) ) and
@@ -305,7 +317,8 @@ private module Cached {
305317 TFieldContent ( FieldDecl f ) or
306318 TTupleContent ( int index ) { exists ( any ( TupleExpr te ) .getElement ( index ) ) } or
307319 TEnumContent ( ParamDecl f ) { exists ( EnumElementDecl d | d .getAParam ( ) = f ) } or
308- TCollectionContent ( )
320+ TCollectionContent ( ) or
321+ TCapturedVariableContent ( CapturedVariable v )
309322}
310323
311324/**
@@ -371,7 +384,7 @@ private module ParameterNodes {
371384 predicate isParameterOf ( DataFlowCallable c , ParameterPosition pos ) { none ( ) }
372385
373386 /** Gets the parameter associated with this node, if any. */
374- ParamDecl getParameter ( ) { none ( ) }
387+ override ParamDecl getParameter ( ) { none ( ) }
375388 }
376389
377390 class SourceParameterNode extends ParameterNodeImpl , TSourceParameterNode {
@@ -658,7 +671,7 @@ private module ReturnNodes {
658671 result = TDataFlowFunc ( param .getDeclaringFunction ( ) )
659672 }
660673
661- ParamDecl getParameter ( ) { result = param }
674+ override ParamDecl getParameter ( ) { result = param }
662675
663676 override Location getLocationImpl ( ) { result = exit .getLocation ( ) }
664677
@@ -785,6 +798,136 @@ private module OutNodes {
785798
786799import OutNodes
787800
801+ private predicate closureFlowStep ( Expr e1 , Expr e2 ) {
802+ // simpleLocalFlowStep(exprNode(e1), exprNode(e2)) // TODO: find out why the java version uses simpleAstFlowStep... probably due to non-monotonic recursion
803+ // or
804+ exists ( Ssa:: WriteDefinition def |
805+ def .getARead ( ) .getNode ( ) .asAstNode ( ) = e2 and
806+ def .assigns ( any ( CfgNode cfg | cfg .getNode ( ) .asAstNode ( ) = e1 ) )
807+ )
808+ }
809+
810+ private module CaptureInput implements VariableCapture:: InputSig {
811+ private import swift as S
812+ private import codeql.swift.controlflow.BasicBlocks as B
813+
814+ class Location = S:: Location ;
815+
816+ class BasicBlock instanceof B:: BasicBlock {
817+ string toString ( ) { result = super .toString ( ) }
818+
819+ Callable getEnclosingCallable ( ) { result = super .getScope ( ) }
820+
821+ Location getLocation ( ) { result = super .getLocation ( ) }
822+ }
823+
824+ BasicBlock getImmediateBasicBlockDominator ( BasicBlock bb ) { result .( B:: BasicBlock ) .dominates ( bb ) }
825+
826+ BasicBlock getABasicBlockSuccessor ( BasicBlock bb ) { result = bb .( B:: BasicBlock ) .getASuccessor ( ) }
827+
828+ //TODO: support capture of `this` in lambdas
829+ class CapturedVariable instanceof S:: CapturedDecl {
830+ string toString ( ) { result = super .toString ( ) }
831+
832+ Callable getCallable ( ) { result = super .getScope ( ) }
833+
834+ Location getLocation ( ) { result = super .getLocation ( ) }
835+ }
836+
837+ class CapturedParameter extends CapturedVariable {
838+ CapturedParameter ( ) { this .( S:: CapturedDecl ) .getDecl ( ) instanceof S:: ParamDecl }
839+ }
840+
841+ class Expr instanceof S:: AstNode {
842+ string toString ( ) { result = super .toString ( ) }
843+
844+ Location getLocation ( ) { result = super .getLocation ( ) }
845+
846+ predicate hasCfgNode ( BasicBlock bb , int i ) {
847+ this = bb .( B:: BasicBlock ) .getNode ( i ) .getNode ( ) .asAstNode ( )
848+ }
849+ }
850+
851+ class VariableWrite extends Expr {
852+ CapturedVariable variable ;
853+ Expr source ;
854+
855+ VariableWrite ( ) {
856+ exists ( S:: VarDecl varDecl |
857+ variable .( S:: CapturedDecl ) .getDecl ( ) = varDecl and
858+ variable .getCallable ( ) = this .( S:: AstNode ) .getEnclosingCallable ( )
859+ |
860+ exists ( S:: Assignment a | this = a |
861+ a .getDest ( ) .( DeclRefExpr ) .getDecl ( ) = varDecl and
862+ source = a .getSource ( )
863+ )
864+ or
865+ exists ( S:: PatternBindingDecl pbd , S:: NamedPattern np |
866+ this = pbd and pbd .getAPattern ( ) = np
867+ |
868+ np .getVarDecl ( ) = varDecl and
869+ source = np .getMatchingExpr ( )
870+ )
871+ // TODO: support multiple variables in LHS of =, in both of above cases.
872+ )
873+ }
874+
875+ CapturedVariable getVariable ( ) { result = variable }
876+
877+ Expr getSource ( ) { result = source }
878+ }
879+
880+ class VariableRead extends Expr instanceof S:: DeclRefExpr {
881+ CapturedVariable v ;
882+
883+ VariableRead ( ) { this .getCapturedDecl ( ) = v /* TODO: this should be an R-value only. */ }
884+
885+ CapturedVariable getVariable ( ) { result = v }
886+ }
887+
888+ class ClosureExpr extends Expr instanceof S:: Callable {
889+ ClosureExpr ( ) { any ( S:: CapturedDecl c ) .getScope ( ) = this }
890+
891+ predicate hasBody ( Callable body ) { this = body }
892+
893+ predicate hasAliasedAccess ( Expr f ) {
894+ closureFlowStep + ( this , f ) and not closureFlowStep ( f , _)
895+ /* TODO: understand why this is intra-procedural */ }
896+ }
897+
898+ class Callable extends S:: Callable {
899+ predicate isConstructor ( ) { this instanceof S:: Initializer }
900+ }
901+ }
902+
903+ class CapturedVariable = CaptureInput:: CapturedVariable ;
904+
905+ class CapturedParameter = CaptureInput:: CapturedParameter ;
906+
907+ module CaptureFlow = VariableCapture:: Flow< CaptureInput > ;
908+
909+ private CaptureFlow:: ClosureNode asClosureNode ( Node n ) {
910+ result = n .( CaptureNode ) .getSynthesizedCaptureNode ( ) or
911+ result .( CaptureFlow:: ExprNode ) .getExpr ( ) = n .asExpr ( ) or
912+ result .( CaptureFlow:: ExprPostUpdateNode ) .getExpr ( ) =
913+ n .( PostUpdateNode ) .getPreUpdateNode ( ) .asExpr ( ) or
914+ result .( CaptureFlow:: ParameterNode ) .getParameter ( ) .( CapturedDecl ) .getDecl ( ) = n .getParameter ( ) or
915+ result .( CaptureFlow:: ThisParameterNode ) .getCallable ( ) .getSelfParam ( ) = n .getParameter ( ) or
916+ result .( CaptureFlow:: MallocNode ) .getClosureExpr ( ) = n .getCfgNode ( ) .getNode ( ) .asAstNode ( ) // TODO: figure out why the java version had PostUpdateNode logic here
917+ }
918+
919+ private predicate captureStoreStep ( Node node1 , Content:: CapturedVariableContent c , Node node2 ) {
920+ CaptureFlow:: storeStep ( asClosureNode ( node1 ) , c .getVariable ( ) , asClosureNode ( node2 ) )
921+ }
922+
923+ private predicate captureReadStep ( Node node1 , Content:: CapturedVariableContent c , Node node2 ) {
924+ CaptureFlow:: readStep ( asClosureNode ( node1 ) , c .getVariable ( ) , asClosureNode ( node2 ) )
925+ }
926+
927+ predicate captureValueStep ( Node node1 , Node node2 ) {
928+ CaptureFlow:: localFlowStep ( asClosureNode ( node1 ) , asClosureNode ( node2 ) )
929+ }
930+
788931predicate jumpStep ( Node pred , Node succ ) {
789932 FlowSummaryImpl:: Private:: Steps:: summaryJumpStep ( pred .( FlowSummaryNode ) .getSummaryNode ( ) ,
790933 succ .( FlowSummaryNode ) .getSummaryNode ( ) )
0 commit comments