Skip to content

Commit 292bc67

Browse files
authored
Merge pull request #10620 from hvitved/ruby/call-graph-protected-methods
Ruby: Account for `protected` methods in call graph
2 parents 32d002e + dd7458a commit 292bc67

File tree

7 files changed

+2044
-1803
lines changed

7 files changed

+2044
-1803
lines changed

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

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -317,15 +317,20 @@ private module Cached {
317317
exists(Module tp |
318318
instanceMethodCall(call, tp, method) and
319319
result = lookupMethod(tp, method) and
320-
if result.(Method).isPrivate()
321-
then
322-
call.getReceiver().getExpr() instanceof SelfVariableAccess and
323-
// For now, we restrict the scope of top-level declarations to their file.
324-
// This may remove some plausible targets, but also removes a lot of
325-
// implausible targets
326-
if result.getEnclosingModule() instanceof Toplevel
327-
then result.getFile() = call.getFile()
320+
(
321+
if result.(Method).isPrivate()
322+
then
323+
call.getReceiver().getExpr() instanceof SelfVariableAccess and
324+
// For now, we restrict the scope of top-level declarations to their file.
325+
// This may remove some plausible targets, but also removes a lot of
326+
// implausible targets
327+
if result.getEnclosingModule() instanceof Toplevel
328+
then result.getFile() = call.getFile()
329+
else any()
328330
else any()
331+
) and
332+
if result.(Method).isProtected()
333+
then result = lookupMethod(call.getExpr().getEnclosingModule().getModule(), method)
329334
else any()
330335
)
331336
or

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

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -49,53 +49,62 @@ calls.rb:
4949
# 105| Module
5050
#-----| super -> Object
5151

52-
# 112| Object
52+
# 115| Object
5353
#-----| super -> BasicObject
5454
#-----| include -> Kernel
5555
#-----| prepend -> A
5656

57-
# 117| Hash
57+
# 120| Hash
5858
#-----| super -> Object
5959

60-
# 122| Array
60+
# 125| Array
6161
#-----| super -> Object
6262

63-
# 162| S
63+
# 165| S
6464
#-----| super -> Object
6565

66-
# 168| A
66+
# 171| A
6767
#-----| super -> S
6868
#-----| super -> B
6969
#-----| prepend -> A::B
7070

71-
# 173| B
71+
# 176| B
7272
#-----| super -> S
7373

74-
# 187| Singletons
74+
# 190| Singletons
7575
#-----| super -> Object
7676

77-
# 307| SelfNew
77+
# 310| SelfNew
7878
#-----| super -> Object
7979

80-
# 322| C1
80+
# 325| C1
8181
#-----| super -> Object
8282

83-
# 328| C2
83+
# 331| C2
8484
#-----| super -> C1
8585

86-
# 334| C3
86+
# 337| C3
8787
#-----| super -> C2
8888

89-
# 374| SingletonOverride1
89+
# 377| SingletonOverride1
9090
#-----| super -> Object
9191

92-
# 399| SingletonOverride2
92+
# 402| SingletonOverride2
9393
#-----| super -> SingletonOverride1
9494

95-
# 414| ConditionalInstanceMethods
95+
# 417| ConditionalInstanceMethods
9696
#-----| super -> Object
9797

98-
# 477| ExtendSingletonMethod
98+
# 480| ExtendSingletonMethod
99+
100+
# 490| ProtectedMethodInModule
101+
102+
# 496| ProtectedMethods
103+
#-----| super -> Object
104+
#-----| include -> ProtectedMethodInModule
105+
106+
# 515| ProtectedMethodsSub
107+
#-----| super -> ProtectedMethods
99108

100109
hello.rb:
101110
# 1| EnglishWords

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

Lines changed: 314 additions & 284 deletions
Large diffs are not rendered by default.

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

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,11 @@ def puts x; old_puts x end
103103
end
104104

105105
class Module
106+
alias :old_include :include
106107
def module_eval; end
107-
def include; end
108+
def include x
109+
old_include x
110+
end
108111
def prepend; end
109112
def private; end
110113
end
@@ -447,7 +450,7 @@ def m5
447450
ConditionalInstanceMethods.new.m3 # currently unable to resolve
448451
ConditionalInstanceMethods.new.m4 # currently unable to resolve
449452
ConditionalInstanceMethods.new.m5 # NoMethodError
450-
exit
453+
451454
EsotericInstanceMethods = Class.new do
452455
[0,1,2].each do
453456
def foo
@@ -483,3 +486,39 @@ def singleton
483486
end
484487

485488
ExtendSingletonMethod.singleton # currently unable to resolve
489+
490+
module ProtectedMethodInModule
491+
protected def foo
492+
puts "ProtectedMethodInModule#foo"
493+
end
494+
end
495+
496+
class ProtectedMethods
497+
include ProtectedMethodInModule
498+
499+
protected def bar
500+
puts "ProtectedMethods#bar"
501+
end
502+
503+
def baz
504+
foo
505+
bar
506+
ProtectedMethods.new.foo
507+
ProtectedMethods.new.bar
508+
end
509+
end
510+
511+
ProtectedMethods.new.foo # NoMethodError
512+
ProtectedMethods.new.bar # NoMethodError
513+
ProtectedMethods.new.baz
514+
515+
class ProtectedMethodsSub < ProtectedMethods
516+
def baz
517+
foo
518+
ProtectedMethodsSub.new.foo
519+
end
520+
end
521+
522+
ProtectedMethodsSub.new.foo # NoMethodError
523+
ProtectedMethodsSub.new.bar # NoMethodError
524+
ProtectedMethodsSub.new.baz

0 commit comments

Comments
 (0)