@@ -186,9 +186,9 @@ private predicate superCall(CfgNodes::ExprNodes::CallCfgNode call, Module superC
186
186
187
187
pragma [ nomagic]
188
188
private predicate instanceMethodCall ( CfgNodes:: ExprNodes:: CallCfgNode call , Module tp , string method ) {
189
- exists ( DataFlow:: LocalSourceNode sourceNode , Module m , boolean exact |
190
- flowsToMethodCall ( call , sourceNode , method ) and
191
- sourceNode = trackInstance ( m , exact )
189
+ exists ( DataFlow:: Node receiver , Module m , boolean exact |
190
+ methodCall ( call , receiver , method ) and
191
+ receiver = trackInstance ( m , exact )
192
192
|
193
193
tp = m
194
194
or
@@ -239,7 +239,7 @@ private predicate selfInToplevel(SelfVariable self, Module m) {
239
239
*
240
240
* the SSA definition for `c` is introduced by matching on `C`.
241
241
*/
242
- predicate asModulePattern ( SsaDefinitionNode def , Module m ) {
242
+ private predicate asModulePattern ( SsaDefinitionNode def , Module m ) {
243
243
exists ( AsPattern ap |
244
244
m = resolveConstantReadAccess ( ap .getPattern ( ) ) and
245
245
def .getDefinition ( ) .( Ssa:: WriteDefinition ) .getWriteAccess ( ) = ap .getVariableAccess ( )
@@ -258,7 +258,7 @@ predicate asModulePattern(SsaDefinitionNode def, Module m) {
258
258
*
259
259
* the two reads of `object` are adjacent, and the second is checked to have type `C`.
260
260
*/
261
- predicate hasAdjacentTypeCheckedReads (
261
+ private predicate hasAdjacentTypeCheckedReads (
262
262
Ssa:: Definition def , CfgNodes:: ExprCfgNode read1 , CfgNodes:: ExprCfgNode read2 , Module m
263
263
) {
264
264
exists (
@@ -322,11 +322,9 @@ private module Cached {
322
322
// def c.singleton; end # <- result
323
323
// c.singleton # <- call
324
324
// ```
325
- exists ( DataFlow:: Node sourceNode |
326
- methodCall ( call , sourceNode , method ) or
327
- flowsToMethodCall ( call , sourceNode , method )
328
- |
329
- sourceNode = trackSingletonMethodOnInstance ( result , method )
325
+ exists ( DataFlow:: Node receiver |
326
+ methodCall ( call , receiver , method ) and
327
+ receiver = trackSingletonMethodOnInstance ( result , method )
330
328
)
331
329
or
332
330
// singleton method defined on a module
@@ -445,7 +443,7 @@ private DataFlow::LocalSourceNode trackModuleAccess(Module m) {
445
443
}
446
444
447
445
pragma [ nomagic]
448
- private DataFlow:: LocalSourceNode trackInstance ( Module tp , boolean exact , TypeTracker t ) {
446
+ private DataFlow:: Node trackInstance ( Module tp , boolean exact , TypeTracker t ) {
449
447
t .start ( ) and
450
448
(
451
449
result .asExpr ( ) .getExpr ( ) instanceof NilLiteral and
@@ -554,23 +552,30 @@ private DataFlow::LocalSourceNode trackInstance(Module tp, boolean exact, TypeTr
554
552
)
555
553
}
556
554
555
+ private predicate localFlowStep ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo , StepSummary summary ) {
556
+ localFlowStepTypeTracker ( nodeFrom , nodeTo ) and
557
+ summary .toString ( ) = "level"
558
+ }
559
+
557
560
/**
558
561
* We exclude steps into `self` parameters and type checked variables. For those,
559
562
* we instead rely on the type of the enclosing module resp. the type being checked
560
563
* against, and apply an open-world assumption when determining possible dispatch
561
564
* targets.
562
565
*/
563
566
pragma [ nomagic]
564
- private DataFlow:: LocalSourceNode trackInstanceRec (
565
- Module tp , TypeTracker t , boolean exact , StepSummary summary
566
- ) {
567
- StepSummary:: step ( trackInstance ( tp , exact , t ) , result , summary ) and
567
+ private DataFlow:: Node trackInstanceRec ( Module tp , TypeTracker t , boolean exact , StepSummary summary ) {
568
+ exists ( DataFlow:: Node mid | mid = trackInstance ( tp , exact , t ) |
569
+ StepSummary:: smallstep ( mid , result , summary )
570
+ or
571
+ localFlowStep ( mid , result , summary )
572
+ ) and
568
573
not result instanceof SelfParameterNode and
569
574
not hasAdjacentTypeCheckedReads ( _, _, result .asExpr ( ) , _)
570
575
}
571
576
572
577
pragma [ nomagic]
573
- private DataFlow:: LocalSourceNode trackInstance ( Module tp , boolean exact ) {
578
+ private DataFlow:: Node trackInstance ( Module tp , boolean exact ) {
574
579
result = trackInstance ( tp , exact , TypeTracker:: end ( ) )
575
580
}
576
581
@@ -683,16 +688,6 @@ predicate singletonMethodOnInstance(MethodBase method, string name, Expr object)
683
688
not exists ( resolveConstantReadAccess ( object ) )
684
689
}
685
690
686
- /**
687
- * Same as `singletonMethodOnInstance`, but where `n` is the post-update node
688
- * of the object that is the target of the singleton method `method`.
689
- */
690
- predicate singletonMethodOnInstancePostUpdate (
691
- MethodBase method , string name , DataFlow:: PostUpdateNode n
692
- ) {
693
- singletonMethodOnInstance ( method , name , n .getPreUpdateNode ( ) .asExpr ( ) .getExpr ( ) )
694
- }
695
-
696
691
/**
697
692
* Holds if there is reverse flow from `nodeFrom` to `nodeTo` via a parameter.
698
693
*
@@ -723,44 +718,46 @@ predicate singletonMethodOnInstancePostUpdate(
723
718
* ```
724
719
*/
725
720
pragma [ nomagic]
726
- private predicate paramReturnFlow ( DataFlow:: PostUpdateNode nodeFrom , DataFlow:: PostUpdateNode nodeTo ) {
721
+ private predicate paramReturnFlow (
722
+ DataFlow:: Node nodeFrom , DataFlow:: PostUpdateNode nodeTo , StepSummary summary
723
+ ) {
727
724
exists (
728
725
CfgNodes:: ExprNodes:: CallCfgNode call , DataFlow:: Node arg , DataFlow:: ParameterNode p ,
729
726
Expr nodeFromPreExpr
730
727
|
731
728
TypeTrackerSpecific:: callStep ( call , arg , p ) and
732
729
nodeTo .getPreUpdateNode ( ) = arg and
733
- nodeFromPreExpr = nodeFrom .getPreUpdateNode ( ) .asExpr ( ) .getExpr ( )
730
+ summary .toString ( ) = "return" and
731
+ (
732
+ nodeFromPreExpr = nodeFrom .( DataFlow:: PostUpdateNode ) .getPreUpdateNode ( ) .asExpr ( ) .getExpr ( )
733
+ or
734
+ nodeFromPreExpr = nodeFrom .asExpr ( ) .getExpr ( ) and
735
+ singletonMethodOnInstance ( _, _, nodeFromPreExpr )
736
+ )
734
737
|
735
738
nodeFromPreExpr = p .getParameter ( ) .( NamedParameter ) .getVariable ( ) .getAnAccess ( )
736
739
or
737
740
nodeFromPreExpr = p .( SelfParameterNode ) .getSelfVariable ( ) .getAnAccess ( )
738
741
)
739
742
}
740
743
741
- // Since post-update nodes are not (and should not be) `LocalSourceNode`s in general,
742
- // we need to do local flow manually
743
- pragma [ nomagic]
744
- private predicate argPostUpdateFlowsTo ( DataFlow:: PostUpdateNode arg , DataFlow:: Node n ) {
745
- paramReturnFlow ( _, arg ) and
746
- n = arg
747
- or
748
- exists ( DataFlow:: Node mid |
749
- argPostUpdateFlowsTo ( arg , mid ) and
750
- localFlowStepTypeTracker ( mid , n )
751
- )
752
- }
753
-
754
744
pragma [ nomagic]
755
745
private DataFlow:: Node trackSingletonMethodOnInstance ( MethodBase method , string name , TypeTracker t ) {
756
746
t .start ( ) and
757
- singletonMethodOnInstancePostUpdate ( method , name , result )
747
+ singletonMethodOnInstance ( method , name , result . asExpr ( ) . getExpr ( ) )
758
748
or
759
749
exists ( TypeTracker t2 , StepSummary summary |
760
750
result = trackSingletonMethodOnInstanceRec ( method , name , t2 , summary ) and
761
751
t = t2 .append ( summary ) and
762
- // do not step over redefinitions
763
- not singletonMethodOnInstancePostUpdate ( _, name , result )
752
+ // Stop flow at redefinitions.
753
+ //
754
+ // Example:
755
+ // ```rb
756
+ // def x.foo; end
757
+ // def x.foo; end
758
+ // x.foo # <- we want to resolve this call to the second definition only
759
+ // ```
760
+ not singletonMethodOnInstance ( _, name , result .asExpr ( ) .getExpr ( ) )
764
761
)
765
762
}
766
763
@@ -769,15 +766,11 @@ private DataFlow::Node trackSingletonMethodOnInstanceRec(
769
766
MethodBase method , string name , TypeTracker t , StepSummary summary
770
767
) {
771
768
exists ( DataFlow:: Node mid | mid = trackSingletonMethodOnInstance ( method , name , t ) |
772
- StepSummary:: step ( mid , result , summary )
769
+ StepSummary:: smallstep ( mid , result , summary )
773
770
or
774
- // include flow out through parameters
775
- paramReturnFlow ( mid , result ) and
776
- summary .toString ( ) = "return"
771
+ paramReturnFlow ( mid , result , summary )
777
772
or
778
- // include flow starting from an output argument
779
- argPostUpdateFlowsTo ( mid , result ) and
780
- summary .toString ( ) = "level"
773
+ localFlowStep ( mid , result , summary )
781
774
)
782
775
}
783
776
0 commit comments