@@ -39,7 +39,7 @@ class SourceNode extends DataFlow::Node {
39
39
* Holds if this node flows into `sink` in zero or more local (that is,
40
40
* intra-procedural) steps.
41
41
*/
42
- predicate flowsTo ( DataFlow:: Node sink ) { hasLocalSource ( sink , this ) }
42
+ predicate flowsTo ( DataFlow:: Node sink ) { Cached :: hasLocalSource ( sink , this ) }
43
43
44
44
/**
45
45
* Holds if this node flows into `sink` in zero or more local (that is,
@@ -51,8 +51,7 @@ class SourceNode extends DataFlow::Node {
51
51
* Gets a reference (read or write) of property `propName` on this node.
52
52
*/
53
53
DataFlow:: PropRef getAPropertyReference ( string propName ) {
54
- result = getAPropertyReference ( ) and
55
- result .getPropertyName ( ) = propName
54
+ Cached:: namedPropRef ( this , propName , result )
56
55
}
57
56
58
57
/**
@@ -78,7 +77,11 @@ class SourceNode extends DataFlow::Node {
78
77
/**
79
78
* Gets a reference (read or write) of any property on this node.
80
79
*/
81
- DataFlow:: PropRef getAPropertyReference ( ) { flowsTo ( result .getBase ( ) ) }
80
+ DataFlow:: PropRef getAPropertyReference ( ) {
81
+ Cached:: namedPropRef ( this , _, result )
82
+ or
83
+ Cached:: dynamicPropRef ( this , result )
84
+ }
82
85
83
86
/**
84
87
* Gets a read of any property on this node.
@@ -113,11 +116,8 @@ class SourceNode extends DataFlow::Node {
113
116
* that is, `o.m(...)` or `o[p](...)`.
114
117
*/
115
118
DataFlow:: CallNode getAMethodCall ( string methodName ) {
116
- exists ( PropAccess pacc |
117
- pacc = result .getCalleeNode ( ) .asExpr ( ) .getUnderlyingReference ( ) and
118
- flowsToExpr ( pacc .getBase ( ) ) and
119
- pacc .getPropertyName ( ) = methodName
120
- )
119
+ result = getAMemberInvocation ( methodName ) and
120
+ Cached:: isSyntacticMethodCall ( result )
121
121
}
122
122
123
123
/**
@@ -148,7 +148,7 @@ class SourceNode extends DataFlow::Node {
148
148
/**
149
149
* Gets an invocation (with our without `new`) of this node.
150
150
*/
151
- DataFlow:: InvokeNode getAnInvocation ( ) { flowsTo ( result . getCalleeNode ( ) ) }
151
+ DataFlow:: InvokeNode getAnInvocation ( ) { Cached :: invocation ( this , result ) }
152
152
153
153
/**
154
154
* Gets a function call to this node.
@@ -192,21 +192,61 @@ class SourceNode extends DataFlow::Node {
192
192
}
193
193
194
194
/**
195
- * Holds if `source` is a `SourceNode` that can reach `sink` via local flow steps.
196
- *
197
- * The slightly backwards parametering ordering is to force correct indexing.
195
+ * Cached predicates used by the member predicates in `SourceNode`.
198
196
*/
199
197
cached
200
- private predicate hasLocalSource ( DataFlow:: Node sink , DataFlow:: Node source ) {
201
- // Declaring `source` to be a `SourceNode` currently causes a redundant check in the
202
- // recursive case, so instead we check it explicitly here.
203
- source = sink and
204
- source instanceof DataFlow:: SourceNode
205
- or
206
- exists ( DataFlow:: Node mid |
207
- hasLocalSource ( mid , source ) and
208
- DataFlow:: localFlowStep ( mid , sink )
209
- )
198
+ private module Cached {
199
+ /**
200
+ * Holds if `source` is a `SourceNode` that can reach `sink` via local flow steps.
201
+ *
202
+ * The slightly backwards parametering ordering is to force correct indexing.
203
+ */
204
+ cached
205
+ predicate hasLocalSource ( DataFlow:: Node sink , DataFlow:: Node source ) {
206
+ // Declaring `source` to be a `SourceNode` currently causes a redundant check in the
207
+ // recursive case, so instead we check it explicitly here.
208
+ source = sink and
209
+ source instanceof DataFlow:: SourceNode
210
+ or
211
+ exists ( DataFlow:: Node mid |
212
+ hasLocalSource ( mid , source ) and
213
+ DataFlow:: localFlowStep ( mid , sink )
214
+ )
215
+ }
216
+
217
+ /**
218
+ * Holds if `base` flows to the base of `ref` and `ref` has property name `prop`.
219
+ */
220
+ cached
221
+ predicate namedPropRef ( DataFlow:: SourceNode base , string prop , DataFlow:: PropRef ref ) {
222
+ hasLocalSource ( ref .getBase ( ) , base ) and
223
+ ref .getPropertyName ( ) = prop
224
+ }
225
+
226
+ /**
227
+ * Holds if `base` flows to the base of `ref` and `ref` has no known property name.
228
+ */
229
+ cached
230
+ predicate dynamicPropRef ( DataFlow:: SourceNode base , DataFlow:: PropRef ref ) {
231
+ hasLocalSource ( ref .getBase ( ) , base ) and
232
+ not exists ( ref .getPropertyName ( ) )
233
+ }
234
+
235
+ /**
236
+ * Holds if `func` flows to the callee of `invoke`.
237
+ */
238
+ cached
239
+ predicate invocation ( DataFlow:: SourceNode func , DataFlow:: InvokeNode invoke ) {
240
+ hasLocalSource ( invoke .getCalleeNode ( ) , func )
241
+ }
242
+
243
+ /**
244
+ * Holds if `invoke` has the syntactic shape of a method call.
245
+ */
246
+ cached
247
+ predicate isSyntacticMethodCall ( DataFlow:: CallNode call ) {
248
+ call .getCalleeNode ( ) .asExpr ( ) .getUnderlyingReference ( ) instanceof PropAccess
249
+ }
210
250
}
211
251
212
252
module SourceNode {
0 commit comments