@@ -10,16 +10,17 @@ private import codeql.ruby.dataflow.FlowSummary
1010private import codeql.ruby.dataflow.SSA
1111
1212/**
13- * A `LocalSourceNode` for a `self` variable. This is either an implicit `self`
14- * parameter or an implicit SSA entry definition.
13+ * A `LocalSourceNode` for a `self` variable. This is the implicit `self`
14+ * parameter, when it exists, otherwise the implicit SSA entry definition.
1515 */
1616private class SelfLocalSourceNode extends DataFlow:: LocalSourceNode {
1717 private SelfVariable self ;
1818
1919 SelfLocalSourceNode ( ) {
20- self = this .( SelfParameterNode ) .getSelfVariable ( )
20+ self = this .( SelfParameterNodeImpl ) .getSelfVariable ( )
2121 or
22- self = this .( SsaSelfDefinitionNode ) .getVariable ( )
22+ self = this .( SsaSelfDefinitionNode ) .getVariable ( ) and
23+ not LocalFlow:: localFlowSsaParamInput ( _, this )
2324 }
2425
2526 /** Gets the `self` variable. */
@@ -469,23 +470,43 @@ private module Cached {
469470
470471import Cached
471472
473+ pragma [ nomagic]
474+ private predicate stepCallProj ( DataFlow:: LocalSourceNode nodeFrom , StepSummary summary ) {
475+ StepSummary:: stepCall ( nodeFrom , _, summary )
476+ }
477+
478+ pragma [ nomagic]
479+ private predicate isNotSelf ( DataFlow:: Node n ) { not n instanceof SelfParameterNodeImpl }
480+
472481pragma [ nomagic]
473482private DataFlow:: LocalSourceNode trackModuleAccess ( Module m , TypeTracker t ) {
474483 t .start ( ) and m = resolveConstantReadAccess ( result .asExpr ( ) .getExpr ( ) )
475484 or
476- exists ( TypeTracker t2 , StepSummary summary |
477- result = trackModuleAccessRec ( m , t2 , summary ) and t = t2 .append ( summary )
485+ // We exclude steps into `self` parameters, and instead rely on the type of the
486+ // enclosing module
487+ isNotSelf ( result ) and
488+ (
489+ exists ( TypeTracker t2 | t = t2 .stepNoCall ( trackModuleAccess ( m , t2 ) , result ) )
490+ or
491+ exists ( StepSummary summary |
492+ // non-linear recursion
493+ StepSummary:: stepCall ( trackModuleAccessCall ( m , t , summary ) , result , summary )
494+ )
478495 )
479496}
480497
481- /**
482- * We exclude steps into `self` parameters, and instead rely on the type of the
483- * enclosing module.
484- */
498+ bindingset [ t , summary ]
499+ pragma [ inline_late ]
500+ private TypeTracker append ( TypeTracker t , StepSummary summary ) { result = t . append ( summary ) }
501+
485502pragma [ nomagic]
486- private DataFlow:: LocalSourceNode trackModuleAccessRec ( Module m , TypeTracker t , StepSummary summary ) {
487- StepSummary:: step ( trackModuleAccess ( m , t ) , result , summary ) and
488- not result instanceof SelfParameterNode
503+ private DataFlow:: LocalSourceNode trackModuleAccessCall ( Module m , TypeTracker t , StepSummary summary ) {
504+ exists ( TypeTracker t2 |
505+ // non-linear recursion
506+ result = trackModuleAccess ( m , t2 ) and
507+ stepCallProj ( result , summary ) and
508+ t = append ( t2 , summary )
509+ )
489510}
490511
491512pragma [ nomagic]
@@ -498,7 +519,7 @@ private predicate hasUserDefinedNew(Module m) {
498519 exists ( DataFlow:: MethodNode method |
499520 // not `getAnAncestor` because singleton methods cannot be included
500521 singletonMethodOnModule ( method .asCallableAstNode ( ) , "new" , m .getSuperClass * ( ) ) and
501- not method .getSelfParameter ( ) .getAMethodCall ( "allocate" ) .flowsTo ( method .getAReturningNode ( ) )
522+ not method .getSelfParameter ( ) .getAMethodCall ( "allocate" ) .flowsTo ( method .getAReturnNode ( ) )
502523 )
503524}
504525
@@ -610,6 +631,49 @@ private predicate isInstance(DataFlow::Node n, Module tp, boolean exact) {
610631 exact = false
611632}
612633
634+ private predicate localFlowStep ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo , StepSummary summary ) {
635+ localFlowStepTypeTracker ( nodeFrom , nodeTo ) and
636+ summary .toString ( ) = "level"
637+ }
638+
639+ pragma [ nomagic]
640+ private predicate hasAdjacentTypeCheckedReads ( DataFlow:: Node node ) {
641+ hasAdjacentTypeCheckedReads ( _, _, node .asExpr ( ) , _)
642+ }
643+
644+ pragma [ nomagic]
645+ private predicate smallStepNoCallForTrackInstance0 (
646+ DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo , StepSummary summary
647+ ) {
648+ // We exclude steps into `self` parameters. For those, we instead rely on the type of
649+ // the enclosing module
650+ StepSummary:: smallstepNoCall ( nodeFrom , nodeTo , summary ) and
651+ isNotSelf ( nodeTo )
652+ or
653+ // We exclude steps into type checked variables. For those, we instead rely on the
654+ // type being checked against
655+ localFlowStep ( nodeFrom , nodeTo , summary ) and
656+ not hasAdjacentTypeCheckedReads ( nodeTo )
657+ }
658+
659+ pragma [ nomagic]
660+ private predicate smallStepNoCallForTrackInstance0Proj ( DataFlow:: Node nodeFrom , StepSummary summary ) {
661+ smallStepNoCallForTrackInstance0 ( nodeFrom , _, summary )
662+ }
663+
664+ bindingset [ t, nodeFrom]
665+ pragma [ inline_late]
666+ pragma [ noopt]
667+ private TypeTracker smallStepNoCallForTrackInstance (
668+ TypeTracker t , DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo
669+ ) {
670+ exists ( StepSummary summary |
671+ smallStepNoCallForTrackInstance0Proj ( nodeFrom , summary ) and
672+ result = t .append ( summary ) and
673+ smallStepNoCallForTrackInstance0 ( nodeFrom , nodeTo , summary )
674+ )
675+ }
676+
613677pragma [ nomagic]
614678private DataFlow:: Node trackInstance ( Module tp , boolean exact , TypeTracker t ) {
615679 t .start ( ) and
@@ -631,35 +695,33 @@ private DataFlow::Node trackInstance(Module tp, boolean exact, TypeTracker t) {
631695 )
632696 )
633697 or
634- exists ( TypeTracker t2 , StepSummary summary |
635- result = trackInstanceRec ( tp , t2 , exact , summary ) and t = t2 .append ( summary )
698+ exists ( TypeTracker t2 |
699+ t = smallStepNoCallForTrackInstance ( t2 , trackInstance ( tp , exact , t2 ) , result )
700+ )
701+ or
702+ // We exclude steps into `self` parameters. For those, we instead rely on the type of
703+ // the enclosing module
704+ exists ( StepSummary summary |
705+ // non-linear recursion
706+ StepSummary:: smallstepCall ( trackInstanceCall ( tp , t , exact , summary ) , result , summary ) and
707+ isNotSelf ( result )
636708 )
637- }
638-
639- private predicate localFlowStep ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo , StepSummary summary ) {
640- localFlowStepTypeTracker ( nodeFrom , nodeTo ) and
641- summary .toString ( ) = "level"
642709}
643710
644711pragma [ nomagic]
645- private predicate hasAdjacentTypeCheckedReads ( DataFlow:: Node node ) {
646- hasAdjacentTypeCheckedReads ( _ , _, node . asExpr ( ) , _ )
712+ private predicate smallStepCallProj ( DataFlow:: Node nodeFrom , StepSummary summary ) {
713+ StepSummary :: smallstepCall ( nodeFrom , _, summary )
647714}
648715
649- /**
650- * We exclude steps into `self` parameters and type checked variables. For those,
651- * we instead rely on the type of the enclosing module resp. the type being checked
652- * against, and apply an open-world assumption when determining possible dispatch
653- * targets.
654- */
655716pragma [ nomagic]
656- private DataFlow:: Node trackInstanceRec ( Module tp , TypeTracker t , boolean exact , StepSummary summary ) {
657- exists ( DataFlow:: Node mid | mid = trackInstance ( tp , exact , t ) |
658- StepSummary:: smallstep ( mid , result , summary ) and
659- not result instanceof SelfParameterNode
660- or
661- localFlowStep ( mid , result , summary ) and
662- not hasAdjacentTypeCheckedReads ( result )
717+ private DataFlow:: Node trackInstanceCall (
718+ Module tp , TypeTracker t , boolean exact , StepSummary summary
719+ ) {
720+ exists ( TypeTracker t2 |
721+ // non-linear recursion
722+ result = trackInstance ( tp , exact , t2 ) and
723+ smallStepCallProj ( result , summary ) and
724+ t = append ( t2 , summary )
663725 )
664726}
665727
@@ -710,20 +772,27 @@ pragma[nomagic]
710772private DataFlow:: LocalSourceNode trackBlock ( Block block , TypeTracker t ) {
711773 t .start ( ) and result .asExpr ( ) .getExpr ( ) = block
712774 or
713- exists ( TypeTracker t2 , StepSummary summary |
714- result = trackBlockRec ( block , t2 , summary ) and
715- t = t2 .append ( summary )
775+ // We exclude steps into `self` parameters, which may happen when the code
776+ // base contains implementations of `call`.
777+ isNotSelf ( result ) and
778+ (
779+ exists ( TypeTracker t2 | t = t2 .stepNoCall ( trackBlock ( block , t2 ) , result ) )
780+ or
781+ exists ( StepSummary summary |
782+ // non-linear recursion
783+ StepSummary:: stepCall ( trackBlockCall ( block , t , summary ) , result , summary )
784+ )
716785 )
717786}
718787
719- /**
720- * We exclude steps into `self` parameters, which may happen when the code
721- * base contains implementations of `call`.
722- */
723788pragma [ nomagic]
724- private DataFlow:: LocalSourceNode trackBlockRec ( Block block , TypeTracker t , StepSummary summary ) {
725- StepSummary:: step ( trackBlock ( block , t ) , result , summary ) and
726- not result instanceof SelfParameterNode
789+ private DataFlow:: LocalSourceNode trackBlockCall ( Block block , TypeTracker t , StepSummary summary ) {
790+ exists ( TypeTracker t2 |
791+ // non-linear recursion
792+ result = trackBlock ( block , t2 ) and
793+ stepCallProj ( result , summary ) and
794+ t = append ( t2 , summary )
795+ )
727796}
728797
729798pragma [ nomagic]
@@ -942,7 +1011,7 @@ private predicate paramReturnFlow(
9421011 |
9431012 nodeFromPreExpr = p .getParameter ( ) .( NamedParameter ) .getVariable ( ) .getAnAccess ( )
9441013 or
945- nodeFromPreExpr = p .( SelfParameterNode ) .getSelfVariable ( ) .getAnAccess ( )
1014+ nodeFromPreExpr = p .( SelfParameterNodeImpl ) .getSelfVariable ( ) .getAnAccess ( )
9461015 )
9471016}
9481017
@@ -951,31 +1020,53 @@ private DataFlow::Node trackSingletonMethodOnInstance(MethodBase method, string
9511020 t .start ( ) and
9521021 singletonMethodOnInstance ( method , name , result .asExpr ( ) .getExpr ( ) )
9531022 or
954- exists ( TypeTracker t2 , StepSummary summary |
955- result = trackSingletonMethodOnInstanceRec ( method , name , t2 , summary ) and
956- t = t2 .append ( summary ) and
957- // Stop flow at redefinitions.
958- //
959- // Example:
960- // ```rb
961- // def x.foo; end
962- // def x.foo; end
963- // x.foo # <- we want to resolve this call to the second definition only
964- // ```
965- not singletonMethodOnInstance ( _, name , result .asExpr ( ) .getExpr ( ) )
966- )
1023+ (
1024+ exists ( TypeTracker t2 |
1025+ t = t2 .smallstepNoCall ( trackSingletonMethodOnInstance ( method , name , t2 ) , result )
1026+ )
1027+ or
1028+ exists ( StepSummary summary |
1029+ // non-linear recursion
1030+ smallStepCallForTrackSingletonMethodOnInstance ( trackSingletonMethodOnInstanceCall ( method ,
1031+ name , t , summary ) , result , summary )
1032+ )
1033+ ) and
1034+ // Stop flow at redefinitions.
1035+ //
1036+ // Example:
1037+ // ```rb
1038+ // def x.foo; end
1039+ // def x.foo; end
1040+ // x.foo # <- we want to resolve this call to the second definition only
1041+ // ```
1042+ not singletonMethodOnInstance ( _, name , result .asExpr ( ) .getExpr ( ) )
1043+ }
1044+
1045+ pragma [ nomagic]
1046+ private predicate smallStepCallForTrackSingletonMethodOnInstance (
1047+ DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo , StepSummary summary
1048+ ) {
1049+ StepSummary:: smallstepCall ( nodeFrom , nodeTo , summary )
1050+ or
1051+ paramReturnFlow ( nodeFrom , nodeTo , summary )
9671052}
9681053
9691054pragma [ nomagic]
970- private DataFlow:: Node trackSingletonMethodOnInstanceRec (
1055+ private predicate smallStepCallForTrackSingletonMethodOnInstanceProj (
1056+ DataFlow:: Node nodeFrom , StepSummary summary
1057+ ) {
1058+ smallStepCallForTrackSingletonMethodOnInstance ( nodeFrom , _, summary )
1059+ }
1060+
1061+ pragma [ nomagic]
1062+ private DataFlow:: Node trackSingletonMethodOnInstanceCall (
9711063 MethodBase method , string name , TypeTracker t , StepSummary summary
9721064) {
973- exists ( DataFlow:: Node mid | mid = trackSingletonMethodOnInstance ( method , name , t ) |
974- StepSummary:: smallstep ( mid , result , summary )
975- or
976- paramReturnFlow ( mid , result , summary )
977- or
978- localFlowStep ( mid , result , summary )
1065+ exists ( TypeTracker t2 |
1066+ // non-linear recursion
1067+ result = trackSingletonMethodOnInstance ( method , name , t2 ) and
1068+ smallStepCallForTrackSingletonMethodOnInstanceProj ( result , summary ) and
1069+ t = append ( t2 , summary )
9791070 )
9801071}
9811072
0 commit comments