@@ -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,138 @@ private predicate fieldStep(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 ( )
61
- |
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
- )
55
+ private predicate closureFlowStep ( Expr e1 , Expr e2 ) {
56
+ simpleAstFlowStep ( e1 , e2 )
57
+ or
58
+ exists ( SsaVariable v |
59
+ v .getAUse ( ) = e2 and
60
+ v .getAnUltimateDefinition ( ) .( SsaExplicitUpdate ) .getDefiningExpr ( ) .( VariableAssign ) .getSource ( ) =
61
+ e1
71
62
)
72
63
}
73
64
65
+ private module CaptureInput implements VariableCapture:: InputSig {
66
+ private import java as J
67
+
68
+ class Location = J:: Location ;
69
+
70
+ class BasicBlock instanceof J:: BasicBlock {
71
+ string toString ( ) { result = super .toString ( ) }
72
+
73
+ Callable getEnclosingCallable ( ) { result = super .getEnclosingCallable ( ) }
74
+
75
+ Location getLocation ( ) { result = super .getLocation ( ) }
76
+ }
77
+
78
+ BasicBlock getImmediateBasicBlockDominator ( BasicBlock bb ) { bbIDominates ( result , bb ) }
79
+
80
+ BasicBlock getABasicBlockSuccessor ( BasicBlock bb ) {
81
+ result = bb .( J:: BasicBlock ) .getABBSuccessor ( )
82
+ }
83
+
84
+ //TODO: support capture of `this` in lambdas
85
+ class CapturedVariable instanceof LocalScopeVariable {
86
+ CapturedVariable ( ) {
87
+ 2 <=
88
+ strictcount ( J:: Callable c |
89
+ c = this .getCallable ( ) or c = this .getAnAccess ( ) .getEnclosingCallable ( )
90
+ )
91
+ }
92
+
93
+ string toString ( ) { result = super .toString ( ) }
94
+
95
+ Callable getCallable ( ) { result = super .getCallable ( ) }
96
+
97
+ Location getLocation ( ) { result = super .getLocation ( ) }
98
+ }
99
+
100
+ class CapturedParameter extends CapturedVariable instanceof Parameter { }
101
+
102
+ class Expr instanceof J:: Expr {
103
+ string toString ( ) { result = super .toString ( ) }
104
+
105
+ Location getLocation ( ) { result = super .getLocation ( ) }
106
+
107
+ predicate hasCfgNode ( BasicBlock bb , int i ) { this = bb .( J:: BasicBlock ) .getNode ( i ) }
108
+ }
109
+
110
+ class VariableWrite extends Expr instanceof VariableUpdate {
111
+ CapturedVariable v ;
112
+
113
+ VariableWrite ( ) { super .getDestVar ( ) = v }
114
+
115
+ CapturedVariable getVariable ( ) { result = v }
116
+
117
+ Expr getSource ( ) {
118
+ result = this .( VariableAssign ) .getSource ( ) or
119
+ result = this .( AssignOp )
120
+ }
121
+ }
122
+
123
+ class VariableRead extends Expr instanceof RValue {
124
+ CapturedVariable v ;
125
+
126
+ VariableRead ( ) { super .getVariable ( ) = v }
127
+
128
+ CapturedVariable getVariable ( ) { result = v }
129
+ }
130
+
131
+ class ClosureExpr extends Expr instanceof ClassInstanceExpr {
132
+ NestedClass nc ;
133
+
134
+ ClosureExpr ( ) {
135
+ nc .( AnonymousClass ) .getClassInstanceExpr ( ) = this
136
+ or
137
+ nc instanceof LocalClass and
138
+ super .getConstructedType ( ) .getASourceSupertype * ( ) .getSourceDeclaration ( ) = nc
139
+ }
140
+
141
+ predicate hasBody ( Callable body ) { nc .getACallable ( ) = body }
142
+
143
+ predicate hasAliasedAccess ( Expr f ) { closureFlowStep + ( this , f ) and not closureFlowStep ( f , _) }
144
+ }
145
+
146
+ class Callable extends J:: Callable {
147
+ predicate isConstructor ( ) { this instanceof Constructor }
148
+ }
149
+ }
150
+
151
+ class CapturedVariable = CaptureInput:: CapturedVariable ;
152
+
153
+ class CapturedParameter = CaptureInput:: CapturedParameter ;
154
+
155
+ module CaptureFlow = VariableCapture:: Flow< CaptureInput > ;
156
+
157
+ private CaptureFlow:: ClosureNode asClosureNode ( Node n ) {
158
+ result = n .( CaptureNode ) .getSynthesizedCaptureNode ( ) or
159
+ result .( CaptureFlow:: ExprNode ) .getExpr ( ) = n .asExpr ( ) or
160
+ result .( CaptureFlow:: ExprPostUpdateNode ) .getExpr ( ) =
161
+ n .( PostUpdateNode ) .getPreUpdateNode ( ) .asExpr ( ) or
162
+ result .( CaptureFlow:: ParameterNode ) .getParameter ( ) = n .asParameter ( ) or
163
+ result .( CaptureFlow:: ThisParameterNode ) .getCallable ( ) = n .( InstanceParameterNode ) .getCallable ( ) or
164
+ exprNode ( result .( CaptureFlow:: MallocNode ) .getClosureExpr ( ) ) .( PostUpdateNode ) .getPreUpdateNode ( ) =
165
+ n
166
+ }
167
+
168
+ private predicate captureStoreStep ( Node node1 , CapturedVariableContent c , Node node2 ) {
169
+ CaptureFlow:: storeStep ( asClosureNode ( node1 ) , c .getVariable ( ) , asClosureNode ( node2 ) )
170
+ }
171
+
172
+ private predicate captureReadStep ( Node node1 , CapturedVariableContent c , Node node2 ) {
173
+ CaptureFlow:: readStep ( asClosureNode ( node1 ) , c .getVariable ( ) , asClosureNode ( node2 ) )
174
+ }
175
+
176
+ predicate captureValueStep ( Node node1 , Node node2 ) {
177
+ CaptureFlow:: localFlowStep ( asClosureNode ( node1 ) , asClosureNode ( node2 ) )
178
+ }
179
+
74
180
/**
75
181
* Holds if data can flow from `node1` to `node2` through a field or
76
182
* variable capture.
77
183
*/
78
184
predicate jumpStep ( Node node1 , Node node2 ) {
79
185
fieldStep ( node1 , node2 )
80
186
or
81
- variableCaptureStep ( node1 , node2 )
82
- or
83
- variableCaptureStep ( node1 .( PostUpdateNode ) .getPreUpdateNode ( ) , node2 )
84
- or
85
187
any ( AdditionalValueStep a ) .step ( node1 , node2 ) and
86
188
node1 .getEnclosingCallable ( ) != node2 .getEnclosingCallable ( )
87
189
or
@@ -117,6 +219,8 @@ predicate storeStep(Node node1, ContentSet f, Node node2) {
117
219
or
118
220
FlowSummaryImpl:: Private:: Steps:: summaryStoreStep ( node1 .( FlowSummaryNode ) .getSummaryNode ( ) , f ,
119
221
node2 .( FlowSummaryNode ) .getSummaryNode ( ) )
222
+ or
223
+ captureStoreStep ( node1 , f , node2 )
120
224
}
121
225
122
226
/**
@@ -149,6 +253,8 @@ predicate readStep(Node node1, ContentSet f, Node node2) {
149
253
or
150
254
FlowSummaryImpl:: Private:: Steps:: summaryReadStep ( node1 .( FlowSummaryNode ) .getSummaryNode ( ) , f ,
151
255
node2 .( FlowSummaryNode ) .getSummaryNode ( ) )
256
+ or
257
+ captureReadStep ( node1 , f , node2 )
152
258
}
153
259
154
260
/**
@@ -231,19 +337,29 @@ private newtype TDataFlowCallable =
231
337
TSummarizedCallable ( SummarizedCallable c ) or
232
338
TFieldScope ( Field f )
233
339
340
+ /**
341
+ * A callable or scope enclosing some number of data flow nodes. This can either
342
+ * be a source callable, a synthesized callable for which we have a summary
343
+ * model, or a synthetic scope for a field value node.
344
+ */
234
345
class DataFlowCallable extends TDataFlowCallable {
346
+ /** Gets the source callable corresponding to this callable, if any. */
235
347
Callable asCallable ( ) { this = TSrcCallable ( result ) }
236
348
349
+ /** Gets the summary model callable corresponding to this callable, if any. */
237
350
SummarizedCallable asSummarizedCallable ( ) { this = TSummarizedCallable ( result ) }
238
351
352
+ /** Gets the field corresponding to this callable, if it is a field value scope. */
239
353
Field asFieldScope ( ) { this = TFieldScope ( result ) }
240
354
355
+ /** Gets a textual representation of this callable. */
241
356
string toString ( ) {
242
357
result = this .asCallable ( ) .toString ( ) or
243
358
result = "Synthetic: " + this .asSummarizedCallable ( ) .toString ( ) or
244
359
result = "Field scope: " + this .asFieldScope ( ) .toString ( )
245
360
}
246
361
362
+ /** Gets the location of this callable. */
247
363
Location getLocation ( ) {
248
364
result = this .asCallable ( ) .getLocation ( ) or
249
365
result = this .asSummarizedCallable ( ) .getLocation ( ) or
@@ -406,6 +522,8 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
406
522
*/
407
523
predicate allowParameterReturnInSelf ( ParameterNode p ) {
408
524
FlowSummaryImpl:: Private:: summaryAllowParameterReturnInSelf ( p )
525
+ or
526
+ CaptureFlow:: heuristicAllowInstanceParameterReturnInSelf ( p .( InstanceParameterNode ) .getCallable ( ) )
409
527
}
410
528
411
529
/** An approximated `Content`. */
@@ -447,6 +565,10 @@ ContentApprox getContentApprox(Content c) {
447
565
or
448
566
c instanceof MapValueContent and result = TMapValueContentApprox ( )
449
567
or
568
+ exists ( CapturedVariable v |
569
+ c = TCapturedVariableContent ( v ) and result = TCapturedVariableContentApprox ( v )
570
+ )
571
+ or
450
572
c instanceof SyntheticFieldContent and result = TSyntheticFieldApproxContent ( )
451
573
}
452
574
0 commit comments