@@ -186,9 +186,9 @@ private predicate superCall(CfgNodes::ExprNodes::CallCfgNode call, Module superC
186186
187187pragma [ nomagic]
188188private 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 )
192192 |
193193 tp = m
194194 or
@@ -239,7 +239,7 @@ private predicate selfInToplevel(SelfVariable self, Module m) {
239239 *
240240 * the SSA definition for `c` is introduced by matching on `C`.
241241 */
242- predicate asModulePattern ( SsaDefinitionNode def , Module m ) {
242+ private predicate asModulePattern ( SsaDefinitionNode def , Module m ) {
243243 exists ( AsPattern ap |
244244 m = resolveConstantReadAccess ( ap .getPattern ( ) ) and
245245 def .getDefinition ( ) .( Ssa:: WriteDefinition ) .getWriteAccess ( ) = ap .getVariableAccess ( )
@@ -258,7 +258,7 @@ predicate asModulePattern(SsaDefinitionNode def, Module m) {
258258 *
259259 * the two reads of `object` are adjacent, and the second is checked to have type `C`.
260260 */
261- predicate hasAdjacentTypeCheckedReads (
261+ private predicate hasAdjacentTypeCheckedReads (
262262 Ssa:: Definition def , CfgNodes:: ExprCfgNode read1 , CfgNodes:: ExprCfgNode read2 , Module m
263263) {
264264 exists (
@@ -322,11 +322,9 @@ private module Cached {
322322 // def c.singleton; end # <- result
323323 // c.singleton # <- call
324324 // ```
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 )
330328 )
331329 or
332330 // singleton method defined on a module
@@ -445,7 +443,7 @@ private DataFlow::LocalSourceNode trackModuleAccess(Module m) {
445443}
446444
447445pragma [ nomagic]
448- private DataFlow:: LocalSourceNode trackInstance ( Module tp , boolean exact , TypeTracker t ) {
446+ private DataFlow:: Node trackInstance ( Module tp , boolean exact , TypeTracker t ) {
449447 t .start ( ) and
450448 (
451449 result .asExpr ( ) .getExpr ( ) instanceof NilLiteral and
@@ -554,23 +552,30 @@ private DataFlow::LocalSourceNode trackInstance(Module tp, boolean exact, TypeTr
554552 )
555553}
556554
555+ private predicate localFlowStep ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo , StepSummary summary ) {
556+ localFlowStepTypeTracker ( nodeFrom , nodeTo ) and
557+ summary .toString ( ) = "level"
558+ }
559+
557560/**
558561 * We exclude steps into `self` parameters and type checked variables. For those,
559562 * we instead rely on the type of the enclosing module resp. the type being checked
560563 * against, and apply an open-world assumption when determining possible dispatch
561564 * targets.
562565 */
563566pragma [ 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
568573 not result instanceof SelfParameterNode and
569574 not hasAdjacentTypeCheckedReads ( _, _, result .asExpr ( ) , _)
570575}
571576
572577pragma [ nomagic]
573- private DataFlow:: LocalSourceNode trackInstance ( Module tp , boolean exact ) {
578+ private DataFlow:: Node trackInstance ( Module tp , boolean exact ) {
574579 result = trackInstance ( tp , exact , TypeTracker:: end ( ) )
575580}
576581
@@ -683,16 +688,6 @@ predicate singletonMethodOnInstance(MethodBase method, string name, Expr object)
683688 not exists ( resolveConstantReadAccess ( object ) )
684689}
685690
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-
696691/**
697692 * Holds if there is reverse flow from `nodeFrom` to `nodeTo` via a parameter.
698693 *
@@ -723,44 +718,46 @@ predicate singletonMethodOnInstancePostUpdate(
723718 * ```
724719 */
725720pragma [ 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+ ) {
727724 exists (
728725 CfgNodes:: ExprNodes:: CallCfgNode call , DataFlow:: Node arg , DataFlow:: ParameterNode p ,
729726 Expr nodeFromPreExpr
730727 |
731728 TypeTrackerSpecific:: callStep ( call , arg , p ) and
732729 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+ )
734737 |
735738 nodeFromPreExpr = p .getParameter ( ) .( NamedParameter ) .getVariable ( ) .getAnAccess ( )
736739 or
737740 nodeFromPreExpr = p .( SelfParameterNode ) .getSelfVariable ( ) .getAnAccess ( )
738741 )
739742}
740743
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-
754744pragma [ nomagic]
755745private DataFlow:: Node trackSingletonMethodOnInstance ( MethodBase method , string name , TypeTracker t ) {
756746 t .start ( ) and
757- singletonMethodOnInstancePostUpdate ( method , name , result )
747+ singletonMethodOnInstance ( method , name , result . asExpr ( ) . getExpr ( ) )
758748 or
759749 exists ( TypeTracker t2 , StepSummary summary |
760750 result = trackSingletonMethodOnInstanceRec ( method , name , t2 , summary ) and
761751 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 ( ) )
764761 )
765762}
766763
@@ -769,15 +766,11 @@ private DataFlow::Node trackSingletonMethodOnInstanceRec(
769766 MethodBase method , string name , TypeTracker t , StepSummary summary
770767) {
771768 exists ( DataFlow:: Node mid | mid = trackSingletonMethodOnInstance ( method , name , t ) |
772- StepSummary:: step ( mid , result , summary )
769+ StepSummary:: smallstep ( mid , result , summary )
773770 or
774- // include flow out through parameters
775- paramReturnFlow ( mid , result ) and
776- summary .toString ( ) = "return"
771+ paramReturnFlow ( mid , result , summary )
777772 or
778- // include flow starting from an output argument
779- argPostUpdateFlowsTo ( mid , result ) and
780- summary .toString ( ) = "level"
773+ localFlowStep ( mid , result , summary )
781774 )
782775}
783776
0 commit comments