@@ -252,8 +252,8 @@ module API {
252
252
* Holds if `ref` is a use of a node that should have an incoming edge from the root
253
253
* node labeled `lbl` in the API graph.
254
254
*/
255
- cached
256
- predicate useRoot ( string lbl , DataFlow:: Node ref ) {
255
+ pragma [ nomagic ]
256
+ private predicate useRoot ( string lbl , DataFlow:: Node ref ) {
257
257
exists ( string name , ExprNodes:: ConstantAccessCfgNode access , ConstantReadAccess read |
258
258
access = ref .asExpr ( ) and
259
259
lbl = Label:: member ( read .getName ( ) ) and
@@ -268,64 +268,48 @@ module API {
268
268
}
269
269
270
270
/**
271
- * Holds if `ref` is a use of a node that should have an incoming edge from use node
272
- * `base` labeled `lbl` in the API graph .
271
+ * Holds if `ref` is a use of a node that should have an incoming edge labeled `lbl`,
272
+ * from a use node that flows to `node` .
273
273
*/
274
- cached
275
- predicate useUse ( DataFlow:: LocalSourceNode base , string lbl , DataFlow:: Node ref ) {
276
- exists ( ExprCfgNode node |
277
- // First, we find a predecessor of the node `ref` that we want to determine. The predecessor
278
- // is any node that is a type-tracked use of a data flow node (`src`), which is itself a
279
- // reference to the API node `base`. Thus, `pred` and `src` both represent uses of `base`.
280
- //
281
- // Once we have identified the predecessor, we define its relation to the successor `ref` as
282
- // well as the label on the edge from `pred` to `ref`. This label describes the nature of
283
- // the relationship between `pred` and `ref`.
284
- useExpr ( node , base )
285
- |
286
- // // Referring to an attribute on a node that is a use of `base`:
287
- // pred = `Rails` part of `Rails::Whatever`
288
- // lbl = `Whatever`
289
- // ref = `Rails::Whatever`
290
- exists ( ExprNodes:: ConstantAccessCfgNode c , ConstantReadAccess read |
291
- not exists ( resolveTopLevel ( read ) ) and
292
- node = c .getScopeExpr ( ) and
293
- lbl = Label:: member ( read .getName ( ) ) and
294
- ref .asExpr ( ) = c and
295
- read = c .getExpr ( )
296
- )
297
- or
298
- // Calling a method on a node that is a use of `base`
299
- exists ( ExprNodes:: MethodCallCfgNode call , string name |
300
- node = call .getReceiver ( ) and
301
- name = call .getExpr ( ) .getMethodName ( ) and
302
- lbl = Label:: return ( name ) and
303
- name != "new" and
304
- ref .asExpr ( ) = call
305
- )
306
- or
307
- // Calling the `new` method on a node that is a use of `base`, which creates a new instance
308
- exists ( ExprNodes:: MethodCallCfgNode call |
309
- node = call .getReceiver ( ) and
310
- lbl = Label:: instance ( ) and
311
- call .getExpr ( ) .getMethodName ( ) = "new" and
312
- ref .asExpr ( ) = call
313
- )
274
+ private predicate useStep ( string lbl , ExprCfgNode node , DataFlow:: Node ref ) {
275
+ // // Referring to an attribute on a node that is a use of `base`:
276
+ // pred = `Rails` part of `Rails::Whatever`
277
+ // lbl = `Whatever`
278
+ // ref = `Rails::Whatever`
279
+ exists ( ExprNodes:: ConstantAccessCfgNode c , ConstantReadAccess read |
280
+ not exists ( resolveTopLevel ( read ) ) and
281
+ node = c .getScopeExpr ( ) and
282
+ lbl = Label:: member ( read .getName ( ) ) and
283
+ ref .asExpr ( ) = c and
284
+ read = c .getExpr ( )
285
+ )
286
+ or
287
+ // Calling a method on a node that is a use of `base`
288
+ exists ( ExprNodes:: MethodCallCfgNode call , string name |
289
+ node = call .getReceiver ( ) and
290
+ name = call .getExpr ( ) .getMethodName ( ) and
291
+ lbl = Label:: return ( name ) and
292
+ name != "new" and
293
+ ref .asExpr ( ) = call
294
+ )
295
+ or
296
+ // Calling the `new` method on a node that is a use of `base`, which creates a new instance
297
+ exists ( ExprNodes:: MethodCallCfgNode call |
298
+ node = call .getReceiver ( ) and
299
+ lbl = Label:: instance ( ) and
300
+ call .getExpr ( ) .getMethodName ( ) = "new" and
301
+ ref .asExpr ( ) = call
314
302
)
315
303
}
316
304
317
305
pragma [ nomagic]
318
306
private predicate isUse ( DataFlow:: Node nd ) {
319
307
useRoot ( _, nd )
320
308
or
321
- useUse ( _, _, nd )
322
- }
323
-
324
- pragma [ nomagic]
325
- private predicate useExpr ( ExprCfgNode node , DataFlow:: LocalSourceNode src ) {
326
- exists ( DataFlow:: LocalSourceNode pred |
327
- pred = trackUseNode ( src ) and
328
- pred .flowsTo ( any ( DataFlow:: ExprNode n | n .getExprNode ( ) = node ) )
309
+ exists ( ExprCfgNode node , DataFlow:: LocalSourceNode pred |
310
+ pred = pruneUseNodeFwd ( ) and
311
+ pred .flowsTo ( any ( DataFlow:: ExprNode n | n .getExprNode ( ) = node ) ) and
312
+ useStep ( _, node , nd )
329
313
)
330
314
}
331
315
@@ -335,26 +319,56 @@ module API {
335
319
cached
336
320
predicate use ( TApiNode nd , DataFlow:: Node ref ) { nd = MkUse ( ref ) }
337
321
322
+ private DataFlow:: LocalSourceNode pruneUseNodeFwd ( TypeTracker t ) {
323
+ t .start ( ) and
324
+ isUse ( result )
325
+ or
326
+ exists ( TypeTracker t2 | result = pruneUseNodeFwd ( t2 ) .track ( t2 , t ) )
327
+ }
328
+
329
+ private DataFlow:: LocalSourceNode pruneUseNodeFwd ( ) {
330
+ result = pruneUseNodeFwd ( TypeTracker:: end ( ) )
331
+ }
332
+
333
+ private DataFlow:: Node pruneUseNodeRev ( TypeBackTracker tb ) {
334
+ result = pruneUseNodeFwd ( ) and
335
+ tb .start ( )
336
+ or
337
+ exists ( TypeBackTracker tb2 , DataFlow:: LocalSourceNode mid , TypeTracker t |
338
+ mid = pruneUseNodeRev ( tb2 ) and
339
+ result = mid .backtrack ( tb2 , tb ) and
340
+ pragma [ only_bind_out ] ( result ) = pruneUseNodeFwd ( t ) and
341
+ pragma [ only_bind_out ] ( t ) = pragma [ only_bind_out ] ( tb ) .getACompatibleTypeTracker ( )
342
+ )
343
+ }
344
+
345
+ private DataFlow:: LocalSourceNode pruneUseNodeRev ( ) {
346
+ result = pruneUseNodeRev ( TypeBackTracker:: end ( ) ) and
347
+ isUse ( result )
348
+ }
349
+
338
350
/**
339
351
* Gets a data-flow node to which `src`, which is a use of an API-graph node, flows.
340
352
*
341
- * The flow from `src` to that node may be inter-procedural.
353
+ * The flow from `src` to the returned node may be inter-procedural.
342
354
*/
343
- private DataFlow:: LocalSourceNode trackUseNode ( DataFlow:: Node src , TypeTracker t ) {
344
- // Declaring `src` to be a `LocalSourceNode` currently causes a redundant check in the
345
- // recursive case, so instead we check it explicitly here.
346
- src instanceof DataFlow:: LocalSourceNode and
347
- t .start ( ) and
348
- isUse ( src ) and
349
- result = src
355
+ private DataFlow:: Node trackUseNode ( DataFlow:: LocalSourceNode src , TypeTracker t ) {
356
+ result = src and
357
+ result = pruneUseNodeRev ( ) and
358
+ t .start ( )
350
359
or
351
- exists ( TypeTracker t2 | result = trackUseNode ( src , t2 ) .track ( t2 , t ) )
360
+ exists ( TypeTracker t2 , DataFlow:: LocalSourceNode mid , TypeBackTracker tb |
361
+ mid = trackUseNode ( src , t2 ) and
362
+ result = mid .track ( t2 , t ) and
363
+ pragma [ only_bind_out ] ( result ) = pruneUseNodeRev ( tb ) and
364
+ pragma [ only_bind_out ] ( t ) = pragma [ only_bind_out ] ( tb ) .getACompatibleTypeTracker ( )
365
+ )
352
366
}
353
367
354
368
/**
355
369
* Gets a data-flow node to which `src`, which is a use of an API-graph node, flows.
356
370
*
357
- * The flow from `src` to that node may be inter-procedural.
371
+ * The flow from `src` to the returned node may be inter-procedural.
358
372
*/
359
373
cached
360
374
DataFlow:: LocalSourceNode trackUseNode ( DataFlow:: LocalSourceNode src ) {
@@ -371,9 +385,10 @@ module API {
371
385
pred = MkRoot ( ) and
372
386
useRoot ( lbl , ref )
373
387
or
374
- exists ( DataFlow:: Node nd |
375
- pred = MkUse ( nd ) and
376
- useUse ( nd , lbl , ref )
388
+ exists ( ExprCfgNode node , DataFlow:: Node src |
389
+ pred = MkUse ( src ) and
390
+ trackUseNode ( src ) .flowsTo ( any ( DataFlow:: ExprNode n | n .getExprNode ( ) = node ) ) and
391
+ useStep ( lbl , node , ref )
377
392
)
378
393
)
379
394
}
0 commit comments