@@ -10,16 +10,17 @@ private import codeql.ruby.dataflow.FlowSummary
10
10
private import codeql.ruby.dataflow.SSA
11
11
12
12
/**
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.
15
15
*/
16
16
private class SelfLocalSourceNode extends DataFlow:: LocalSourceNode {
17
17
private SelfVariable self ;
18
18
19
19
SelfLocalSourceNode ( ) {
20
- self = this .( SelfParameterNode ) .getSelfVariable ( )
20
+ self = this .( SelfParameterNodeImpl ) .getSelfVariable ( )
21
21
or
22
- self = this .( SsaSelfDefinitionNode ) .getVariable ( )
22
+ self = this .( SsaSelfDefinitionNode ) .getVariable ( ) and
23
+ not LocalFlow:: localFlowSsaParamInput ( _, this )
23
24
}
24
25
25
26
/** Gets the `self` variable. */
@@ -469,23 +470,43 @@ private module Cached {
469
470
470
471
import Cached
471
472
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
+
472
481
pragma [ nomagic]
473
482
private DataFlow:: LocalSourceNode trackModuleAccess ( Module m , TypeTracker t ) {
474
483
t .start ( ) and m = resolveConstantReadAccess ( result .asExpr ( ) .getExpr ( ) )
475
484
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
+ )
478
495
)
479
496
}
480
497
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
+
485
502
pragma [ 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
+ )
489
510
}
490
511
491
512
pragma [ nomagic]
@@ -498,7 +519,7 @@ private predicate hasUserDefinedNew(Module m) {
498
519
exists ( DataFlow:: MethodNode method |
499
520
// not `getAnAncestor` because singleton methods cannot be included
500
521
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 ( ) )
502
523
)
503
524
}
504
525
@@ -610,6 +631,49 @@ private predicate isInstance(DataFlow::Node n, Module tp, boolean exact) {
610
631
exact = false
611
632
}
612
633
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
+
613
677
pragma [ nomagic]
614
678
private DataFlow:: Node trackInstance ( Module tp , boolean exact , TypeTracker t ) {
615
679
t .start ( ) and
@@ -631,35 +695,33 @@ private DataFlow::Node trackInstance(Module tp, boolean exact, TypeTracker t) {
631
695
)
632
696
)
633
697
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 )
636
708
)
637
- }
638
-
639
- private predicate localFlowStep ( DataFlow:: Node nodeFrom , DataFlow:: Node nodeTo , StepSummary summary ) {
640
- localFlowStepTypeTracker ( nodeFrom , nodeTo ) and
641
- summary .toString ( ) = "level"
642
709
}
643
710
644
711
pragma [ 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 )
647
714
}
648
715
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
- */
655
716
pragma [ 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 )
663
725
)
664
726
}
665
727
@@ -710,20 +772,27 @@ pragma[nomagic]
710
772
private DataFlow:: LocalSourceNode trackBlock ( Block block , TypeTracker t ) {
711
773
t .start ( ) and result .asExpr ( ) .getExpr ( ) = block
712
774
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
+ )
716
785
)
717
786
}
718
787
719
- /**
720
- * We exclude steps into `self` parameters, which may happen when the code
721
- * base contains implementations of `call`.
722
- */
723
788
pragma [ 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
+ )
727
796
}
728
797
729
798
pragma [ nomagic]
@@ -942,7 +1011,7 @@ private predicate paramReturnFlow(
942
1011
|
943
1012
nodeFromPreExpr = p .getParameter ( ) .( NamedParameter ) .getVariable ( ) .getAnAccess ( )
944
1013
or
945
- nodeFromPreExpr = p .( SelfParameterNode ) .getSelfVariable ( ) .getAnAccess ( )
1014
+ nodeFromPreExpr = p .( SelfParameterNodeImpl ) .getSelfVariable ( ) .getAnAccess ( )
946
1015
)
947
1016
}
948
1017
@@ -951,31 +1020,53 @@ private DataFlow::Node trackSingletonMethodOnInstance(MethodBase method, string
951
1020
t .start ( ) and
952
1021
singletonMethodOnInstance ( method , name , result .asExpr ( ) .getExpr ( ) )
953
1022
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 )
967
1052
}
968
1053
969
1054
pragma [ 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 (
971
1063
MethodBase method , string name , TypeTracker t , StepSummary summary
972
1064
) {
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 )
979
1070
)
980
1071
}
981
1072
0 commit comments