@@ -10,6 +10,7 @@ private import semmle.code.java.dataflow.FlowSummary
10
10
private import FlowSummaryImpl as FlowSummaryImpl
11
11
private import DataFlowImplConsistency
12
12
private import DataFlowNodes
13
+ private import codeql.dataflow.VariableCapture as VariableCapture
13
14
import DataFlowNodes:: Private
14
15
15
16
private newtype TReturnKind = TNormalReturnKind ( )
@@ -51,37 +52,119 @@ private predicate staticFieldStep(Node node1, Node node2) {
51
52
)
52
53
}
53
54
54
- /**
55
- * Holds if data can flow from `node1` to `node2` through variable capture.
56
- */
57
- private predicate variableCaptureStep ( Node node1 , ExprNode node2 ) {
58
- exists ( SsaImplicitInit closure , SsaVariable captured |
59
- closure .captures ( captured ) and
60
- node2 .getExpr ( ) = closure .getAFirstUse ( )
55
+ private module CaptureInput implements VariableCapture:: InputSig {
56
+ private import java as J
57
+
58
+ class Location = J:: Location ;
59
+
60
+ class BasicBlock instanceof J:: BasicBlock {
61
+ string toString ( ) { result = super .toString ( ) }
62
+
63
+ DataFlowCallable getEnclosingCallable ( ) { result .asCallable ( ) = super .getEnclosingCallable ( ) }
64
+ }
65
+
66
+ BasicBlock getImmediateBasicBlockDominator ( BasicBlock bb ) { bbIDominates ( result , bb ) }
67
+
68
+ BasicBlock getABasicBlockSuccessor ( BasicBlock bb ) {
69
+ result = bb .( J:: BasicBlock ) .getABBSuccessor ( )
70
+ }
71
+
72
+ //TODO: support capture of `this` in lambdas
73
+ class CapturedVariable instanceof LocalScopeVariable {
74
+ CapturedVariable ( ) {
75
+ 2 <=
76
+ strictcount ( J:: Callable c |
77
+ c = this .getCallable ( ) or c = this .getAnAccess ( ) .getEnclosingCallable ( )
78
+ )
79
+ }
80
+
81
+ string toString ( ) { result = super .toString ( ) }
82
+
83
+ DataFlowCallable getCallable ( ) { result .asCallable ( ) = super .getCallable ( ) }
84
+ }
85
+
86
+ class CapturedParameter extends CapturedVariable instanceof Parameter { }
87
+
88
+ additional predicate capturedVarUpdate (
89
+ J:: BasicBlock bb , int i , CapturedVariable v , VariableUpdate upd
90
+ ) {
91
+ upd .getDestVar ( ) = v and bb .getNode ( i ) = upd
92
+ }
93
+
94
+ additional predicate capturedVarRead ( J:: BasicBlock bb , int i , CapturedVariable v , RValue rv ) {
95
+ v .( LocalScopeVariable ) .getAnAccess ( ) = rv and bb .getNode ( i ) = rv
96
+ }
97
+
98
+ predicate variableWrite ( BasicBlock bb , int i , CapturedVariable v , Location loc ) {
99
+ exists ( VariableUpdate upd | capturedVarUpdate ( bb , i , v , upd ) and loc = upd .getLocation ( ) )
100
+ }
101
+
102
+ predicate variableRead ( BasicBlock bb , int i , CapturedVariable v , Location loc ) {
103
+ exists ( RValue rv | capturedVarRead ( bb , i , v , rv ) and loc = rv .getLocation ( ) )
104
+ }
105
+
106
+ class Callable = DataFlowCallable ;
107
+
108
+ class Call instanceof DataFlowCall {
109
+ string toString ( ) { result = super .toString ( ) }
110
+
111
+ Location getLocation ( ) { result = super .getLocation ( ) }
112
+
113
+ DataFlowCallable getEnclosingCallable ( ) { result = super .getEnclosingCallable ( ) }
114
+
115
+ predicate hasCfgNode ( BasicBlock bb , int i ) { super .asCall ( ) = bb .( J:: BasicBlock ) .getNode ( i ) }
116
+ }
117
+ }
118
+
119
+ class CapturedVariable = CaptureInput:: CapturedVariable ;
120
+
121
+ class CapturedParameter = CaptureInput:: CapturedParameter ;
122
+
123
+ module CaptureFlow = VariableCapture:: Flow< CaptureInput > ;
124
+
125
+ private predicate captureStoreStep ( Node node1 , ClosureContent c , Node node2 ) {
126
+ exists ( BasicBlock bb , int i , CaptureInput:: CapturedVariable v , VariableUpdate upd |
127
+ upd .( VariableAssign ) .getSource ( ) = node1 .asExpr ( ) or
128
+ upd .( AssignOp ) = node1 .asExpr ( )
61
129
|
62
- node1 . asExpr ( ) = captured . getAUse ( )
63
- or
64
- not exists ( captured . getAUse ( ) ) and
65
- exists ( SsaVariable capturedDef | capturedDef = captured . getAnUltimateDefinition ( ) |
66
- capturedDef . ( SsaImplicitInit ) . isParameterDefinition ( node1 . asParameter ( ) ) or
67
- capturedDef . ( SsaExplicitUpdate ) . getDefiningExpr ( ) . ( VariableAssign ) . getSource ( ) =
68
- node1 .asExpr ( ) or
69
- capturedDef . ( SsaExplicitUpdate ) . getDefiningExpr ( ) . ( AssignOp ) = node1 . asExpr ( )
70
- )
130
+ CaptureInput :: capturedVarUpdate ( bb , i , v , upd ) and
131
+ c . getVariable ( ) = v and
132
+ CaptureFlow :: storeStep ( bb , i , v , node2 . ( ClosureNode ) . getCaptureFlowNode ( ) )
133
+ )
134
+ or
135
+ exists ( Parameter p |
136
+ node1 .asParameter ( ) = p and
137
+ c . getVariable ( ) = p and
138
+ CaptureFlow :: parameterStoreStep ( p , node2 . ( ClosureNode ) . getCaptureFlowNode ( ) )
71
139
)
72
140
}
73
141
142
+ private predicate captureReadStep ( Node node1 , ClosureContent c , Node node2 ) {
143
+ exists ( BasicBlock bb , int i , CaptureInput:: CapturedVariable v |
144
+ CaptureFlow:: readStep ( node1 .( ClosureNode ) .getCaptureFlowNode ( ) , bb , i , v ) and
145
+ c .getVariable ( ) = v and
146
+ CaptureInput:: capturedVarRead ( bb , i , v , node2 .asExpr ( ) )
147
+ )
148
+ or
149
+ exists ( Parameter p |
150
+ CaptureFlow:: parameterReadStep ( node1 .( ClosureNode ) .getCaptureFlowNode ( ) , p ) and
151
+ c .getVariable ( ) = p and
152
+ node2 .( PostUpdateNode ) .getPreUpdateNode ( ) .asParameter ( ) = p
153
+ )
154
+ }
155
+
156
+ predicate captureValueStep ( Node node1 , Node node2 ) {
157
+ CaptureFlow:: localFlowStep ( node1 .( ClosureNode ) .getCaptureFlowNode ( ) ,
158
+ node2 .( ClosureNode ) .getCaptureFlowNode ( ) )
159
+ }
160
+
74
161
/**
75
162
* Holds if data can flow from `node1` to `node2` through a static field or
76
163
* variable capture.
77
164
*/
78
165
predicate jumpStep ( Node node1 , Node node2 ) {
79
166
staticFieldStep ( node1 , node2 )
80
167
or
81
- variableCaptureStep ( node1 , node2 )
82
- or
83
- variableCaptureStep ( node1 .( PostUpdateNode ) .getPreUpdateNode ( ) , node2 )
84
- or
85
168
any ( AdditionalValueStep a ) .step ( node1 , node2 ) and
86
169
node1 .getEnclosingCallable ( ) != node2 .getEnclosingCallable ( )
87
170
or
@@ -117,6 +200,8 @@ predicate storeStep(Node node1, Content f, Node node2) {
117
200
or
118
201
FlowSummaryImpl:: Private:: Steps:: summaryStoreStep ( node1 .( FlowSummaryNode ) .getSummaryNode ( ) , f ,
119
202
node2 .( FlowSummaryNode ) .getSummaryNode ( ) )
203
+ or
204
+ captureStoreStep ( node1 , f , node2 )
120
205
}
121
206
122
207
/**
@@ -149,6 +234,8 @@ predicate readStep(Node node1, Content f, Node node2) {
149
234
or
150
235
FlowSummaryImpl:: Private:: Steps:: summaryReadStep ( node1 .( FlowSummaryNode ) .getSummaryNode ( ) , f ,
151
236
node2 .( FlowSummaryNode ) .getSummaryNode ( ) )
237
+ or
238
+ captureReadStep ( node1 , f , node2 )
152
239
}
153
240
154
241
/**
@@ -465,6 +552,8 @@ ContentApprox getContentApprox(Content c) {
465
552
or
466
553
c instanceof MapValueContent and result = TMapValueContentApprox ( )
467
554
or
555
+ exists ( CapturedVariable v | c = TClosureContent ( v ) and result = TClosureContentApprox ( v ) )
556
+ or
468
557
c instanceof SyntheticFieldContent and result = TSyntheticFieldApproxContent ( )
469
558
}
470
559
0 commit comments