Skip to content

Commit 471a596

Browse files
authored
Merge pull request #10895 from hvitved/ruby/track-module-no-self-params
Ruby: Block for steps into `self` parameters in `trackModuleAccess`
2 parents e868cdf + faaead6 commit 471a596

File tree

7 files changed

+1401
-1171
lines changed

7 files changed

+1401
-1171
lines changed

ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -537,9 +537,14 @@ private DataFlow::LocalSourceNode trackModuleAccess(Module m, TypeTracker t) {
537537
)
538538
}
539539

540+
/**
541+
* We exclude steps into `self` parameters, and instead rely on the type of the
542+
* enclosing module.
543+
*/
540544
pragma[nomagic]
541545
private DataFlow::LocalSourceNode trackModuleAccessRec(Module m, TypeTracker t, StepSummary summary) {
542-
StepSummary::step(trackModuleAccess(m, t), result, summary)
546+
StepSummary::step(trackModuleAccess(m, t), result, summary) and
547+
not result instanceof SelfParameterNode
543548
}
544549

545550
pragma[nomagic]
@@ -603,17 +608,22 @@ private predicate isInstance(DataFlow::Node n, Module tp, boolean exact) {
603608
or
604609
exists(RelevantCall call, DataFlow::LocalSourceNode sourceNode |
605610
flowsToMethodCallReceiver(call, sourceNode, "new") and
606-
exact = true and
607611
n.asExpr() = call
608612
|
609613
// `C.new`
610-
sourceNode = trackModuleAccess(tp)
614+
sourceNode = trackModuleAccess(tp) and
615+
exact = true
611616
or
612617
// `self.new` inside a module
613-
selfInModule(sourceNode.(SsaSelfDefinitionNode).getVariable(), tp)
618+
selfInModule(sourceNode.(SsaSelfDefinitionNode).getVariable(), tp) and
619+
exact = true
614620
or
615621
// `self.new` inside a singleton method
616-
selfInMethod(sourceNode.(SsaSelfDefinitionNode).getVariable(), any(SingletonMethod sm), tp)
622+
exists(MethodBase target |
623+
selfInMethod(sourceNode.(SsaSelfDefinitionNode).getVariable(), target, tp) and
624+
singletonMethod(target, _, _) and
625+
exact = false
626+
)
617627
)
618628
or
619629
// `self` reference in method or top-level (but not in module or singleton method,

ruby/ql/test/library-tests/modules/ancestors.expected

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -89,36 +89,45 @@ calls.rb:
8989
# 377| SingletonOverride1
9090
#-----| super -> Object
9191

92-
# 404| SingletonOverride2
92+
# 412| SingletonOverride2
9393
#-----| super -> SingletonOverride1
9494

95-
# 421| ConditionalInstanceMethods
95+
# 433| ConditionalInstanceMethods
9696
#-----| super -> Object
9797

98-
# 484| ExtendSingletonMethod
98+
# 496| ExtendSingletonMethod
9999

100-
# 494| ExtendSingletonMethod2
100+
# 506| ExtendSingletonMethod2
101101

102-
# 500| ExtendSingletonMethod3
102+
# 512| ExtendSingletonMethod3
103103

104-
# 513| ProtectedMethodInModule
104+
# 525| ProtectedMethodInModule
105105

106-
# 519| ProtectedMethods
106+
# 531| ProtectedMethods
107107
#-----| super -> Object
108108
#-----| include -> ProtectedMethodInModule
109109

110-
# 538| ProtectedMethodsSub
110+
# 550| ProtectedMethodsSub
111111
#-----| super -> ProtectedMethods
112112

113-
# 552| SingletonUpCall_Base
113+
# 564| SingletonUpCall_Base
114114
#-----| super -> Object
115115

116-
# 556| SingletonUpCall_Sub
116+
# 568| SingletonUpCall_Sub
117117
#-----| super -> SingletonUpCall_Base
118118

119-
# 564| SingletonUpCall_SubSub
119+
# 576| SingletonUpCall_SubSub
120120
#-----| super -> SingletonUpCall_Sub
121121

122+
# 583| SingletonA
123+
#-----| super -> Object
124+
125+
# 596| SingletonB
126+
#-----| super -> SingletonA
127+
128+
# 605| SingletonC
129+
#-----| super -> SingletonA
130+
122131
hello.rb:
123132
# 1| EnglishWords
124133

ruby/ql/test/library-tests/modules/callgraph.expected

Lines changed: 153 additions & 127 deletions
Large diffs are not rendered by default.

ruby/ql/test/library-tests/modules/calls.rb

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,10 @@ def singleton1
383383
def call_singleton1
384384
singleton1
385385
end
386+
387+
def factory
388+
self.new.instance1
389+
end
386390
end
387391

388392
def self.singleton2
@@ -394,6 +398,10 @@ def self.call_singleton2
394398
end
395399

396400
singleton2
401+
402+
def instance1
403+
puts "SingletonOverride1#instance1"
404+
end
397405
end
398406

399407
SingletonOverride1.singleton1
@@ -411,6 +419,10 @@ def singleton1
411419
def self.singleton2
412420
puts "SingletonOverride2#singleton2"
413421
end
422+
423+
def instance1
424+
puts "SingletonOverride2#instance1"
425+
end
414426
end
415427

416428
SingletonOverride2.singleton1
@@ -567,3 +579,38 @@ def self.singleton2
567579

568580
mid_method
569581
end
582+
583+
class SingletonA
584+
def self.singleton1
585+
end
586+
587+
def self.call_singleton1
588+
singleton1
589+
end
590+
591+
def self.call_call_singleton1
592+
call_singleton1
593+
end
594+
end
595+
596+
class SingletonB < SingletonA
597+
def self.singleton1
598+
end
599+
600+
def self.call_singleton1
601+
singleton1 # should not be able to target `SingletonA:::singleton1` and `SingletonC:::singleton1`
602+
end
603+
end
604+
605+
class SingletonC < SingletonA
606+
def self.singleton1
607+
end
608+
609+
def self.call_singleton1
610+
singleton1 # should not be able to target `SingletonA:::singleton1` and `SingletonB:::singleton1`
611+
end
612+
end
613+
614+
SingletonA.call_call_singleton1
615+
SingletonB.call_call_singleton1
616+
SingletonC.call_call_singleton1

0 commit comments

Comments
 (0)