@@ -21,11 +21,13 @@ private module Cached {
2121 predicate viableParamArg ( DataFlowCall call , ParameterNode p , ArgumentNode arg ) {
2222 exists ( int i |
2323 viableParam ( call , i , p ) and
24- arg .argumentOf ( call , i )
24+ arg .argumentOf ( call , i ) and
25+ compatibleTypes ( getErasedNodeTypeBound ( arg ) , getErasedNodeTypeBound ( p ) )
2526 )
2627 }
2728
2829 /** Provides predicates for calculating flow-through summaries. */
30+ cached
2931 private module FlowThrough {
3032 /**
3133 * The first flow-through approximation:
@@ -216,14 +218,12 @@ private module Cached {
216218 private predicate localFlowStepPlus ( Node node1 , Node node2 ) {
217219 localFlowEntry ( node1 ) and
218220 simpleLocalFlowStep ( node1 , node2 ) and
219- node1 != node2 and
220- Cand:: cand ( _, node2 )
221+ node1 != node2
221222 or
222223 exists ( Node mid |
223224 localFlowStepPlus ( node1 , mid ) and
224225 simpleLocalFlowStep ( mid , node2 ) and
225- not mid instanceof CastNode and
226- Cand:: cand ( _, node2 )
226+ not mid instanceof CastNode
227227 )
228228 }
229229
@@ -238,9 +238,11 @@ private module Cached {
238238 * The final flow-through calculation:
239239 *
240240 * - Input/output access paths are abstracted with a `ContentOption` parameter
241- * that represents the head of the access path.
241+ * that represents the head of the access path. `TContentNone()` means that
242+ * the access path is unrestricted.
242243 * - Types are checked using the `compatibleTypes()` relation.
243244 */
245+ cached
244246 module Final {
245247 /**
246248 * Holds if `p` can flow to `node` in the same callable using only
@@ -250,11 +252,10 @@ private module Cached {
250252 * (if any), and `contentOut` describes the content of `node` that
251253 * it flows to (if any).
252254 */
253- predicate parameterValueFlow (
255+ private predicate parameterValueFlow (
254256 ParameterNode p , Node node , ContentOption contentIn , ContentOption contentOut
255257 ) {
256258 parameterValueFlow0 ( p , node , contentIn , contentOut ) and
257- Cand:: cand ( p , node ) and
258259 if node instanceof CastingNode
259260 then
260261 // normal flow through
@@ -269,19 +270,9 @@ private module Cached {
269270 compatibleTypes ( fIn .getType ( ) , getErasedNodeTypeBound ( node ) )
270271 )
271272 or
272- // setter
273+ // (getter+) setter
273274 exists ( Content fOut |
274- contentIn = TContentNone ( ) and
275275 contentOut .getContent ( ) = fOut and
276- compatibleTypes ( getErasedNodeTypeBound ( p ) , fOut .getType ( ) ) and
277- compatibleTypes ( fOut .getContainerType ( ) , getErasedNodeTypeBound ( node ) )
278- )
279- or
280- // getter+setter
281- exists ( Content fIn , Content fOut |
282- contentIn .getContent ( ) = fIn and
283- contentOut .getContent ( ) = fOut and
284- compatibleTypes ( fIn .getType ( ) , fOut .getType ( ) ) and
285276 compatibleTypes ( fOut .getContainerType ( ) , getErasedNodeTypeBound ( node ) )
286277 )
287278 else any ( )
@@ -312,7 +303,8 @@ private module Cached {
312303 contentOutMid = TContentNone ( ) and
313304 contentIn .getContent ( ) = f and
314305 contentOut = TContentNone ( ) and
315- Cand:: parameterValueFlowReturnCand ( p , _, true , _)
306+ Cand:: parameterValueFlowReturnCand ( p , _, true , _) and
307+ compatibleTypes ( getErasedNodeTypeBound ( p ) , f .getContainerType ( ) )
316308 or
317309 // value (possibly read and then) stored prior to read (same content)
318310 contentIn = contentInMid and
@@ -325,25 +317,30 @@ private module Cached {
325317 parameterValueFlow ( p , mid , contentIn , TContentNone ( ) ) and
326318 storeStep ( mid , f , node ) and
327319 contentOut .getContent ( ) = f
320+ |
321+ contentIn = TContentNone ( ) and
322+ compatibleTypes ( getErasedNodeTypeBound ( p ) , f .getType ( ) )
323+ or
324+ compatibleTypes ( contentIn .getContent ( ) .getType ( ) , f .getType ( ) )
328325 )
329326 or
330327 // flow through: no prior read or store
331328 exists ( ArgumentNode arg |
332329 parameterValueFlowArg ( p , arg , TContentNone ( ) , TContentNone ( ) ) and
333- argumentValueFlowsThrough ( arg , node , contentIn , contentOut )
330+ argumentValueFlowsThrough ( _ , arg , contentIn , contentOut , node )
334331 )
335332 or
336333 // flow through: no read or store inside method
337334 exists ( ArgumentNode arg |
338335 parameterValueFlowArg ( p , arg , contentIn , contentOut ) and
339- argumentValueFlowsThrough ( arg , node , TContentNone ( ) , TContentNone ( ) )
336+ argumentValueFlowsThrough ( _ , arg , TContentNone ( ) , TContentNone ( ) , node )
340337 )
341338 or
342339 // flow through: possible prior read and prior store with compatible
343340 // flow-through method
344341 exists ( ArgumentNode arg , ContentOption contentMid |
345342 parameterValueFlowArg ( p , arg , contentIn , contentMid ) and
346- argumentValueFlowsThrough ( arg , node , contentMid , contentOut )
343+ argumentValueFlowsThrough ( _ , arg , contentMid , contentOut , node )
347344 )
348345 }
349346
@@ -356,15 +353,7 @@ private module Cached {
356353 }
357354
358355 pragma [ nomagic]
359- predicate parameterValueFlowsToPostUpdate (
360- ParameterNode p , PostUpdateNode n , ContentOption contentIn , ContentOption contentOut
361- ) {
362- parameterValueFlow ( p , n , contentIn , contentOut ) and
363- contentOut .hasContent ( )
364- }
365-
366- pragma [ nomagic]
367- predicate argumentValueFlowsThrough0 (
356+ private predicate argumentValueFlowsThrough0 (
368357 DataFlowCall call , ArgumentNode arg , ReturnKindExt kind , ContentOption contentIn ,
369358 ContentOption contentOut
370359 ) {
@@ -374,104 +363,91 @@ private module Cached {
374363 }
375364
376365 /**
377- * Holds if `arg` flows to `out` through a call using only value-preserving steps,
366+ * Holds if `arg` flows to `out` through ` call` using only value-preserving steps,
378367 * not taking call contexts into account.
379368 *
380369 * `contentIn` describes the content of `arg` that can flow to `out` (if any), and
381370 * `contentOut` describes the content of `out` that it flows to (if any).
382371 */
383- private predicate argumentValueFlowsThrough (
384- ArgumentNode arg , Node out , ContentOption contentIn , ContentOption contentOut
372+ cached
373+ predicate argumentValueFlowsThrough (
374+ DataFlowCall call , ArgumentNode arg , ContentOption contentIn , ContentOption contentOut ,
375+ Node out
385376 ) {
386- exists ( DataFlowCall call , ReturnKindExt kind |
377+ exists ( ReturnKindExt kind |
387378 argumentValueFlowsThrough0 ( call , arg , kind , contentIn , contentOut ) and
388379 out = kind .getAnOutNode ( call )
380+ |
381+ // normal flow through
382+ contentIn = TContentNone ( ) and
383+ contentOut = TContentNone ( ) and
384+ compatibleTypes ( getErasedNodeTypeBound ( arg ) , getErasedNodeTypeBound ( out ) )
385+ or
386+ // getter(+setter)
387+ exists ( Content fIn |
388+ contentIn .getContent ( ) = fIn and
389+ compatibleTypes ( getErasedNodeTypeBound ( arg ) , fIn .getContainerType ( ) )
390+ )
391+ or
392+ // setter
393+ exists ( Content fOut |
394+ contentIn = TContentNone ( ) and
395+ contentOut .getContent ( ) = fOut and
396+ compatibleTypes ( getErasedNodeTypeBound ( arg ) , fOut .getType ( ) )
397+ )
389398 )
390399 }
391- }
392400
393- import Final
394- }
401+ /**
402+ * Holds if `p` can flow to the pre-update node associated with post-update
403+ * node `n`, in the same callable, using only value-preserving steps.
404+ */
405+ cached
406+ predicate parameterValueFlowsToPreUpdate ( ParameterNode p , PostUpdateNode n ) {
407+ parameterValueFlow ( p , n .getPreUpdateNode ( ) , TContentNone ( ) , TContentNone ( ) )
408+ }
395409
396- /**
397- * Holds if `p` can flow to the pre-update node associated with post-update
398- * node `n`, in the same callable, using only value-preserving steps.
399- */
400- cached
401- predicate parameterValueFlowsToPreUpdate ( ParameterNode p , PostUpdateNode n ) {
402- FlowThrough:: parameterValueFlow ( p , n .getPreUpdateNode ( ) , TContentNone ( ) , TContentNone ( ) )
403- }
410+ pragma [ nomagic]
411+ private predicate parameterValueFlowsToPostUpdate (
412+ ParameterNode p , PostUpdateNode n , ContentOption contentIn , ContentOption contentOut
413+ ) {
414+ parameterValueFlow ( p , n , contentIn , contentOut ) and
415+ contentOut .hasContent ( )
416+ }
404417
405- /**
406- * Holds if `p` can flow to a return node of kind `kind` in the same
407- * callable using only value-preserving steps.
408- *
409- * `contentIn` describes the content of `p` that can flow to the return
410- * node (if any), and `contentOut` describes the content of the return
411- * node that it flows to (if any).
412- */
413- cached
414- predicate parameterValueFlowReturn (
415- ParameterNode p , Node ret , ReturnKindExt kind , ContentOption contentIn , ContentOption contentOut
416- ) {
417- ret =
418- any ( ReturnNode n |
419- FlowThrough:: parameterValueFlow ( p , n , contentIn , contentOut ) and
420- kind = TValueReturn ( n .getKind ( ) )
421- )
422- or
423- ret =
424- any ( PostUpdateNode n |
425- exists ( ParameterNode p2 , int pos2 |
426- FlowThrough:: parameterValueFlowsToPostUpdate ( p , n , contentIn , contentOut ) and
427- parameterValueFlowsToPreUpdate ( p2 , n ) and
428- p2 .isParameterOf ( _, pos2 ) and
429- kind = TParamUpdate ( pos2 ) and
430- p != p2
431- )
432- )
433- }
418+ /**
419+ * Holds if `p` can flow to a return node of kind `kind` in the same
420+ * callable using only value-preserving steps.
421+ *
422+ * `contentIn` describes the content of `p` that can flow to the return
423+ * node (if any), and `contentOut` describes the content of the return
424+ * node that it flows to (if any).
425+ */
426+ cached
427+ predicate parameterValueFlowReturn (
428+ ParameterNode p , Node ret , ReturnKindExt kind , ContentOption contentIn ,
429+ ContentOption contentOut
430+ ) {
431+ ret =
432+ any ( ReturnNode n |
433+ parameterValueFlow ( p , n , contentIn , contentOut ) and
434+ kind = TValueReturn ( n .getKind ( ) )
435+ )
436+ or
437+ ret =
438+ any ( PostUpdateNode n |
439+ exists ( ParameterNode p2 , int pos2 |
440+ parameterValueFlowsToPostUpdate ( p , n , contentIn , contentOut ) and
441+ parameterValueFlowsToPreUpdate ( p2 , n ) and
442+ p2 .isParameterOf ( _, pos2 ) and
443+ kind = TParamUpdate ( pos2 ) and
444+ p != p2
445+ )
446+ )
447+ }
448+ }
434449
435- /**
436- * Holds if `arg` flows to `out` through `call` using only value-preserving steps.
437- *
438- * `contentIn` describes the content of `arg` that can flow to `out` (if any), and
439- * `contentOut` describes the content of `out` that it flows to (if any).
440- */
441- cached
442- predicate argumentValueFlowsThrough (
443- DataFlowCall call , ArgumentNode arg , ContentOption contentIn , ContentOption contentOut , Node out
444- ) {
445- exists ( ReturnKindExt kind |
446- FlowThrough:: argumentValueFlowsThrough0 ( call , arg , kind , contentIn , contentOut ) and
447- out = kind .getAnOutNode ( call )
448- |
449- // normal flow through
450- contentIn = TContentNone ( ) and
451- contentOut = TContentNone ( ) and
452- compatibleTypes ( getErasedNodeTypeBound ( arg ) , getErasedNodeTypeBound ( out ) )
453- or
454- // getter
455- exists ( Content fIn |
456- contentIn .getContent ( ) = fIn and
457- contentOut = TContentNone ( ) and
458- compatibleTypes ( getErasedNodeTypeBound ( arg ) , fIn .getContainerType ( ) )
459- )
460- or
461- // setter
462- exists ( Content fOut |
463- contentIn = TContentNone ( ) and
464- contentOut .getContent ( ) = fOut and
465- compatibleTypes ( getErasedNodeTypeBound ( arg ) , fOut .getType ( ) )
466- )
467- or
468- // getter+setter
469- exists ( Content fIn , Content fOut |
470- contentIn .getContent ( ) = fIn and
471- contentOut .getContent ( ) = fOut and
472- compatibleTypes ( getErasedNodeTypeBound ( arg ) , fIn .getContainerType ( ) )
473- )
474- )
450+ import Final
475451 }
476452
477453 /**
@@ -495,6 +471,8 @@ private module Cached {
495471 )
496472 }
497473
474+ import FlowThrough
475+
498476 /**
499477 * Holds if the call context `call` either improves virtual dispatch in
500478 * `callable` or if it allows us to prune unreachable nodes in `callable`.
@@ -558,7 +536,7 @@ class ContentOption extends TContentOption {
558536 result = this .getContent ( ) .toString ( )
559537 or
560538 not this .hasContent ( ) and
561- result = ""
539+ result = "<none> "
562540 }
563541}
564542
0 commit comments