@@ -10,6 +10,7 @@ private import codeql.swift.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
10
10
private import codeql.swift.frameworks.StandardLibrary.PointerTypes
11
11
private import codeql.swift.frameworks.StandardLibrary.Array
12
12
private import codeql.swift.frameworks.StandardLibrary.Dictionary
13
+ private import codeql.dataflow.VariableCapture as VariableCapture
13
14
14
15
/** Gets the callable in which this node occurs. */
15
16
DataFlowCallable nodeGetEnclosingCallable ( Node n ) { result = n .( NodeImpl ) .getEnclosingCallable ( ) }
@@ -98,6 +99,16 @@ private class SsaDefinitionNodeImpl extends SsaDefinitionNode, NodeImpl {
98
99
}
99
100
}
100
101
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
+
101
112
private predicate localFlowSsaInput ( Node nodeFrom , Ssa:: Definition def , Ssa:: Definition next ) {
102
113
exists ( BasicBlock bb , int i | def .lastRefRedef ( bb , i , next ) |
103
114
def .definesAt ( _, bb , i ) and
@@ -145,7 +156,8 @@ private module Cached {
145
156
} or
146
157
TDictionarySubscriptNode ( SubscriptExpr e ) {
147
158
e .getBase ( ) .getType ( ) .getCanonicalType ( ) instanceof CanonicalDictionaryType
148
- }
159
+ } or
160
+ TCaptureNode ( CaptureFlow:: SynthesizedCaptureNode cn )
149
161
150
162
private predicate localSsaFlowStepUseUse ( Ssa:: Definition def , Node nodeFrom , Node nodeTo ) {
151
163
def .adjacentReadPair ( nodeFrom .getCfgNode ( ) , nodeTo .getCfgNode ( ) ) and
@@ -305,7 +317,8 @@ private module Cached {
305
317
TFieldContent ( FieldDecl f ) or
306
318
TTupleContent ( int index ) { exists ( any ( TupleExpr te ) .getElement ( index ) ) } or
307
319
TEnumContent ( ParamDecl f ) { exists ( EnumElementDecl d | d .getAParam ( ) = f ) } or
308
- TCollectionContent ( )
320
+ TCollectionContent ( ) or
321
+ TCapturedVariableContent ( CapturedVariable v )
309
322
}
310
323
311
324
/**
@@ -371,7 +384,7 @@ private module ParameterNodes {
371
384
predicate isParameterOf ( DataFlowCallable c , ParameterPosition pos ) { none ( ) }
372
385
373
386
/** Gets the parameter associated with this node, if any. */
374
- ParamDecl getParameter ( ) { none ( ) }
387
+ override ParamDecl getParameter ( ) { none ( ) }
375
388
}
376
389
377
390
class SourceParameterNode extends ParameterNodeImpl , TSourceParameterNode {
@@ -658,7 +671,7 @@ private module ReturnNodes {
658
671
result = TDataFlowFunc ( param .getDeclaringFunction ( ) )
659
672
}
660
673
661
- ParamDecl getParameter ( ) { result = param }
674
+ override ParamDecl getParameter ( ) { result = param }
662
675
663
676
override Location getLocationImpl ( ) { result = exit .getLocation ( ) }
664
677
@@ -785,6 +798,136 @@ private module OutNodes {
785
798
786
799
import OutNodes
787
800
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
+
788
931
predicate jumpStep ( Node pred , Node succ ) {
789
932
FlowSummaryImpl:: Private:: Steps:: summaryJumpStep ( pred .( FlowSummaryNode ) .getSummaryNode ( ) ,
790
933
succ .( FlowSummaryNode ) .getSummaryNode ( ) )
0 commit comments