@@ -10,6 +10,7 @@ private import semmle.code.java.dataflow.FlowSummary
1010private import FlowSummaryImpl as FlowSummaryImpl
1111private import DataFlowImplConsistency
1212private import DataFlowNodes
13+ private import codeql.dataflow.VariableCapture as VariableCapture
1314import DataFlowNodes:: Private
1415
1516private newtype TReturnKind = TNormalReturnKind ( )
@@ -51,37 +52,138 @@ private predicate fieldStep(Node node1, Node node2) {
5152 )
5253}
5354
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
7162 )
7263}
7364
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+
74180/**
75181 * Holds if data can flow from `node1` to `node2` through a field or
76182 * variable capture.
77183 */
78184predicate jumpStep ( Node node1 , Node node2 ) {
79185 fieldStep ( node1 , node2 )
80186 or
81- variableCaptureStep ( node1 , node2 )
82- or
83- variableCaptureStep ( node1 .( PostUpdateNode ) .getPreUpdateNode ( ) , node2 )
84- or
85187 any ( AdditionalValueStep a ) .step ( node1 , node2 ) and
86188 node1 .getEnclosingCallable ( ) != node2 .getEnclosingCallable ( )
87189 or
@@ -117,6 +219,8 @@ predicate storeStep(Node node1, ContentSet f, Node node2) {
117219 or
118220 FlowSummaryImpl:: Private:: Steps:: summaryStoreStep ( node1 .( FlowSummaryNode ) .getSummaryNode ( ) , f ,
119221 node2 .( FlowSummaryNode ) .getSummaryNode ( ) )
222+ or
223+ captureStoreStep ( node1 , f , node2 )
120224}
121225
122226/**
@@ -149,6 +253,8 @@ predicate readStep(Node node1, ContentSet f, Node node2) {
149253 or
150254 FlowSummaryImpl:: Private:: Steps:: summaryReadStep ( node1 .( FlowSummaryNode ) .getSummaryNode ( ) , f ,
151255 node2 .( FlowSummaryNode ) .getSummaryNode ( ) )
256+ or
257+ captureReadStep ( node1 , f , node2 )
152258}
153259
154260/**
@@ -231,19 +337,29 @@ private newtype TDataFlowCallable =
231337 TSummarizedCallable ( SummarizedCallable c ) or
232338 TFieldScope ( Field f )
233339
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+ */
234345class DataFlowCallable extends TDataFlowCallable {
346+ /** Gets the source callable corresponding to this callable, if any. */
235347 Callable asCallable ( ) { this = TSrcCallable ( result ) }
236348
349+ /** Gets the summary model callable corresponding to this callable, if any. */
237350 SummarizedCallable asSummarizedCallable ( ) { this = TSummarizedCallable ( result ) }
238351
352+ /** Gets the field corresponding to this callable, if it is a field value scope. */
239353 Field asFieldScope ( ) { this = TFieldScope ( result ) }
240354
355+ /** Gets a textual representation of this callable. */
241356 string toString ( ) {
242357 result = this .asCallable ( ) .toString ( ) or
243358 result = "Synthetic: " + this .asSummarizedCallable ( ) .toString ( ) or
244359 result = "Field scope: " + this .asFieldScope ( ) .toString ( )
245360 }
246361
362+ /** Gets the location of this callable. */
247363 Location getLocation ( ) {
248364 result = this .asCallable ( ) .getLocation ( ) or
249365 result = this .asSummarizedCallable ( ) .getLocation ( ) or
@@ -406,6 +522,8 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
406522 */
407523predicate allowParameterReturnInSelf ( ParameterNode p ) {
408524 FlowSummaryImpl:: Private:: summaryAllowParameterReturnInSelf ( p )
525+ or
526+ CaptureFlow:: heuristicAllowInstanceParameterReturnInSelf ( p .( InstanceParameterNode ) .getCallable ( ) )
409527}
410528
411529/** An approximated `Content`. */
@@ -447,6 +565,10 @@ ContentApprox getContentApprox(Content c) {
447565 or
448566 c instanceof MapValueContent and result = TMapValueContentApprox ( )
449567 or
568+ exists ( CapturedVariable v |
569+ c = TCapturedVariableContent ( v ) and result = TCapturedVariableContentApprox ( v )
570+ )
571+ or
450572 c instanceof SyntheticFieldContent and result = TSyntheticFieldApproxContent ( )
451573}
452574
0 commit comments