@@ -46,18 +46,19 @@ module LocalFlow {
46
46
)
47
47
}
48
48
49
+ /** Gets the SSA definition node corresponding to parameter `p`. */
50
+ SsaDefinitionNode getParameterDefNode ( NamedParameter p ) {
51
+ exists ( BasicBlock bb , int i |
52
+ bb .getNode ( i ) .getNode ( ) = p .getDefiningAccess ( ) and
53
+ result .getDefinition ( ) .definesAt ( _, bb , i )
54
+ )
55
+ }
56
+
49
57
/**
50
58
* Holds if there is a local flow step from `nodeFrom` to `nodeTo` involving
51
- * SSA definition `def.
59
+ * SSA definition `def` .
52
60
*/
53
61
predicate localSsaFlowStep ( Ssa:: Definition def , Node nodeFrom , Node nodeTo ) {
54
- // Flow from parameter into SSA definition
55
- exists ( BasicBlock bb , int i |
56
- bb .getNode ( i ) .getNode ( ) =
57
- nodeFrom .( ParameterNode ) .getParameter ( ) .( NamedParameter ) .getDefiningAccess ( ) and
58
- nodeTo .( SsaDefinitionNode ) .getDefinition ( ) .definesAt ( _, bb , i )
59
- )
60
- or
61
62
// Flow from assignment into SSA definition
62
63
def .( Ssa:: WriteDefinition ) .assigns ( nodeFrom .asExpr ( ) ) and
63
64
nodeTo .( SsaDefinitionNode ) .getDefinition ( ) = def
@@ -114,6 +115,12 @@ private module Cached {
114
115
newtype TNode =
115
116
TExprNode ( CfgNodes:: ExprCfgNode n ) or
116
117
TReturningNode ( CfgNodes:: ReturningCfgNode n ) or
118
+ TSynthReturnNode ( CfgScope scope , ReturnKind kind ) {
119
+ exists ( ReturningNode ret |
120
+ ret .( NodeImpl ) .getCfgScope ( ) = scope and
121
+ ret .getKind ( ) = kind
122
+ )
123
+ } or
117
124
TSsaDefinitionNode ( Ssa:: Definition def ) or
118
125
TNormalParameterNode ( Parameter p ) { not p instanceof BlockParameter } or
119
126
TSelfParameterNode ( MethodBase m ) or
@@ -139,21 +146,14 @@ private module Cached {
139
146
class TParameterNode =
140
147
TNormalParameterNode or TBlockParameterNode or TSelfParameterNode or TSummaryParameterNode ;
141
148
142
- /**
143
- * This is the local flow predicate that is used as a building block in global
144
- * data flow. It excludes SSA flow through instance fields, as flow through fields
145
- * is handled by the global data-flow library, but includes various other steps
146
- * that are only relevant for global flow.
147
- */
148
- cached
149
- predicate simpleLocalFlowStep ( Node nodeFrom , Node nodeTo ) {
150
- exists ( Ssa:: Definition def | LocalFlow:: localSsaFlowStep ( def , nodeFrom , nodeTo ) )
151
- or
152
- nodeTo .( ParameterNode ) .getParameter ( ) .( OptionalParameter ) .getDefaultValue ( ) =
153
- nodeFrom .asExpr ( ) .getExpr ( )
149
+ private predicate defaultValueFlow ( NamedParameter p , ExprNode e ) {
150
+ p .( OptionalParameter ) .getDefaultValue ( ) = e .getExprNode ( ) .getExpr ( )
154
151
or
155
- nodeTo .( ParameterNode ) .getParameter ( ) .( KeywordParameter ) .getDefaultValue ( ) =
156
- nodeFrom .asExpr ( ) .getExpr ( )
152
+ p .( KeywordParameter ) .getDefaultValue ( ) = e .getExprNode ( ) .getExpr ( )
153
+ }
154
+
155
+ private predicate localFlowStepCommon ( Node nodeFrom , Node nodeTo ) {
156
+ LocalFlow:: localSsaFlowStep ( _, nodeFrom , nodeTo )
157
157
or
158
158
nodeFrom .( SelfParameterNode ) .getMethod ( ) = nodeTo .asExpr ( ) .getExpr ( ) .getEnclosingCallable ( ) and
159
159
nodeTo .asExpr ( ) .getExpr ( ) instanceof Self
@@ -186,12 +186,66 @@ private module Cached {
186
186
) and
187
187
nodeFrom .asExpr ( ) = for .getValue ( )
188
188
)
189
+ }
190
+
191
+ /**
192
+ * This is the local flow predicate that is used as a building block in global
193
+ * data flow.
194
+ */
195
+ cached
196
+ predicate simpleLocalFlowStep ( Node nodeFrom , Node nodeTo ) {
197
+ localFlowStepCommon ( nodeFrom , nodeTo )
198
+ or
199
+ defaultValueFlow ( nodeTo .( ParameterNode ) .getParameter ( ) , nodeFrom )
200
+ or
201
+ nodeTo = LocalFlow:: getParameterDefNode ( nodeFrom .( ParameterNode ) .getParameter ( ) )
202
+ or
203
+ nodeTo .( SynthReturnNode ) .getAnInput ( ) = nodeFrom
189
204
or
190
205
FlowSummaryImpl:: Private:: Steps:: summaryLocalStep ( nodeFrom , nodeTo , true )
191
206
}
192
207
208
+ /** This is the local flow predicate that is exposed. */
193
209
cached
194
- predicate isLocalSourceNode ( Node n ) { not simpleLocalFlowStep + ( any ( ExprNode e ) , n ) }
210
+ predicate localFlowStepImpl ( Node nodeFrom , Node nodeTo ) {
211
+ localFlowStepCommon ( nodeFrom , nodeTo )
212
+ or
213
+ defaultValueFlow ( nodeTo .( ParameterNode ) .getParameter ( ) , nodeFrom )
214
+ or
215
+ nodeTo = LocalFlow:: getParameterDefNode ( nodeFrom .( ParameterNode ) .getParameter ( ) )
216
+ or
217
+ // Simple flow through library code is included in the exposed local
218
+ // step relation, even though flow is technically inter-procedural
219
+ FlowSummaryImpl:: Private:: Steps:: summaryThroughStep ( nodeFrom , nodeTo , true )
220
+ }
221
+
222
+ /** This is the local flow predicate that is used in type tracking. */
223
+ cached
224
+ predicate localFlowStepTypeTracker ( Node nodeFrom , Node nodeTo ) {
225
+ localFlowStepCommon ( nodeFrom , nodeTo )
226
+ or
227
+ exists ( NamedParameter p |
228
+ defaultValueFlow ( p , nodeFrom ) and
229
+ nodeTo = LocalFlow:: getParameterDefNode ( p )
230
+ )
231
+ }
232
+
233
+ cached
234
+ predicate isLocalSourceNode ( Node n ) {
235
+ n instanceof ParameterNode
236
+ or
237
+ // This case should not be needed once we have proper use-use flow
238
+ // for `self`. At that point, the `self`s returned by `trackInstance`
239
+ // in `DataFlowDispatch.qll` should refer to the post-update node,
240
+ // and we can remove this case.
241
+ n instanceof SelfArgumentNode
242
+ or
243
+ not localFlowStepTypeTracker + ( any ( Node e |
244
+ e instanceof ExprNode
245
+ or
246
+ e instanceof ParameterNode
247
+ ) , n )
248
+ }
195
249
196
250
cached
197
251
newtype TContent = TTodoContent ( ) // stub
@@ -208,6 +262,8 @@ predicate nodeIsHidden(Node n) {
208
262
n instanceof SummaryNode
209
263
or
210
264
n instanceof SummaryParameterNode
265
+ or
266
+ n instanceof SynthReturnNode
211
267
}
212
268
213
269
/** An SSA definition, viewed as a node in a data flow graph. */
@@ -234,7 +290,7 @@ class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode {
234
290
* `ControlFlow::Node`s.
235
291
*/
236
292
class ReturningStatementNode extends NodeImpl , TReturningNode {
237
- private CfgNodes:: ReturningCfgNode n ;
293
+ CfgNodes:: ReturningCfgNode n ;
238
294
239
295
ReturningStatementNode ( ) { this = TReturningNode ( n ) }
240
296
@@ -436,6 +492,12 @@ private module ArgumentNodes {
436
492
437
493
import ArgumentNodes
438
494
495
+ /** A data-flow node that represents a value syntactically returned by a callable. */
496
+ abstract class ReturningNode extends Node {
497
+ /** Gets the kind of this return node. */
498
+ abstract ReturnKind getKind ( ) ;
499
+ }
500
+
439
501
/** A data-flow node that represents a value returned by a callable. */
440
502
abstract class ReturnNode extends Node {
441
503
/** Gets the kind of this return node. */
@@ -463,11 +525,9 @@ private module ReturnNodes {
463
525
* A data-flow node that represents an expression returned by a callable,
464
526
* either using an explict `return` statement or as the expression of a method body.
465
527
*/
466
- class ExplicitReturnNode extends ReturnNode , ReturningStatementNode {
467
- private CfgNodes:: ReturningCfgNode n ;
468
-
528
+ class ExplicitReturnNode extends ReturningNode , ReturningStatementNode {
469
529
ExplicitReturnNode ( ) {
470
- isValid ( this . getReturningNode ( ) ) and
530
+ isValid ( n ) and
471
531
n .getASuccessor ( ) .( CfgNodes:: AnnotatedExitNode ) .isNormal ( ) and
472
532
n .getScope ( ) instanceof Callable
473
533
}
@@ -479,7 +539,7 @@ private module ReturnNodes {
479
539
}
480
540
}
481
541
482
- class ExprReturnNode extends ReturnNode , ExprNode {
542
+ class ExprReturnNode extends ReturningNode , ExprNode {
483
543
ExprReturnNode ( ) {
484
544
this .getExprNode ( ) .getASuccessor ( ) .( CfgNodes:: AnnotatedExitNode ) .isNormal ( ) and
485
545
this .( NodeImpl ) .getCfgScope ( ) instanceof Callable
@@ -488,6 +548,34 @@ private module ReturnNodes {
488
548
override ReturnKind getKind ( ) { result instanceof NormalReturnKind }
489
549
}
490
550
551
+ /**
552
+ * A synthetic data-flow node for joining flow from different syntactic
553
+ * returns into a single node.
554
+ *
555
+ * This node only exists to avoid computing the product of a large fan-in
556
+ * with a large fan-out.
557
+ */
558
+ class SynthReturnNode extends NodeImpl , ReturnNode , TSynthReturnNode {
559
+ private CfgScope scope ;
560
+ private ReturnKind kind ;
561
+
562
+ SynthReturnNode ( ) { this = TSynthReturnNode ( scope , kind ) }
563
+
564
+ /** Gets a syntactic return node that flows into this synthetic node. */
565
+ ReturningNode getAnInput ( ) {
566
+ result .( NodeImpl ) .getCfgScope ( ) = scope and
567
+ result .getKind ( ) = kind
568
+ }
569
+
570
+ override ReturnKind getKind ( ) { result = kind }
571
+
572
+ override CfgScope getCfgScope ( ) { result = scope }
573
+
574
+ override Location getLocationImpl ( ) { result = scope .getLocation ( ) }
575
+
576
+ override string toStringImpl ( ) { result = "return " + kind + " in " + scope }
577
+ }
578
+
491
579
private class SummaryReturnNode extends SummaryNode , ReturnNode {
492
580
private ReturnKind rk ;
493
581
@@ -631,7 +719,7 @@ private import PostUpdateNodes
631
719
632
720
/** A node that performs a type cast. */
633
721
class CastNode extends Node {
634
- CastNode ( ) { none ( ) }
722
+ CastNode ( ) { this instanceof ReturningNode }
635
723
}
636
724
637
725
class DataFlowExpr = CfgNodes:: ExprCfgNode ;
0 commit comments