Skip to content

Commit ac59484

Browse files
authored
Merge pull request #10504 from hvitved/ruby/private-methods
Ruby: Two fixes for `private` methods
2 parents 26cf2b3 + 61e9c6f commit ac59484

File tree

8 files changed

+203
-30
lines changed

8 files changed

+203
-30
lines changed

ruby/ql/lib/codeql/ruby/ast/Module.qll

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
private import codeql.ruby.AST
2+
private import codeql.ruby.CFG
23
private import internal.AST
34
private import internal.Module
45
private import internal.TreeSitter
@@ -49,24 +50,54 @@ class Module extends TModule {
4950
}
5051
}
5152

53+
/**
54+
* Gets the enclosing module of `s`, but only if `s` and the module are in the
55+
* same CFG scope. For example, in
56+
*
57+
* ```rb
58+
* module M
59+
* def pub; end
60+
* private def priv; end
61+
* end
62+
* ```
63+
*
64+
* `M` is the enclosing module of `pub` and `priv`, in the same CFG scope, while
65+
* in
66+
*
67+
* ```rb
68+
* module M
69+
* def m
70+
* def nested; end
71+
* end
72+
* end
73+
* ```
74+
*
75+
* `M` is the enclosing module of `m`, in the same CFG scope, while `nested` is not.
76+
*/
77+
pragma[nomagic]
78+
private ModuleBase getEnclosingModuleInSameCfgScope(Stmt s) {
79+
result = s.getEnclosingModule() and
80+
s.getCfgScope() = [result.(CfgScope), result.getCfgScope()]
81+
}
82+
5283
/**
5384
* The base class for classes, singleton classes, and modules.
5485
*/
5586
class ModuleBase extends BodyStmt, Scope, TModuleBase {
5687
/** Gets a method defined in this module/class. */
57-
MethodBase getAMethod() { result = this.getAStmt() }
88+
MethodBase getAMethod() { this = getEnclosingModuleInSameCfgScope(result) }
5889

5990
/** Gets the method named `name` in this module/class, if any. */
6091
MethodBase getMethod(string name) { result = this.getAMethod() and result.getName() = name }
6192

6293
/** Gets a class defined in this module/class. */
63-
ClassDeclaration getAClass() { result = this.getAStmt() }
94+
ClassDeclaration getAClass() { this = getEnclosingModuleInSameCfgScope(result) }
6495

6596
/** Gets the class named `name` in this module/class, if any. */
6697
ClassDeclaration getClass(string name) { result = this.getAClass() and result.getName() = name }
6798

6899
/** Gets a module defined in this module/class. */
69-
ModuleDeclaration getAModule() { result = this.getAStmt() }
100+
ModuleDeclaration getAModule() { this = getEnclosingModuleInSameCfgScope(result) }
70101

71102
/** Gets the module named `name` in this module/class, if any. */
72103
ModuleDeclaration getModule(string name) {

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -302,11 +302,7 @@ private module Cached {
302302
result = lookupMethod(tp, method) and
303303
if result.(Method).isPrivate()
304304
then
305-
exists(SelfVariableAccess self |
306-
self = call.getReceiver().getExpr() and
307-
pragma[only_bind_out](self.getEnclosingModule().getModule().getSuperClass*()) =
308-
pragma[only_bind_out](result.getEnclosingModule().getModule())
309-
) and
305+
call.getReceiver().getExpr() instanceof SelfVariableAccess and
310306
// For now, we restrict the scope of top-level declarations to their file.
311307
// This may remove some plausible targets, but also removes a lot of
312308
// implausible targets

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,9 @@ private.rb:
187187
#-----| super -> Object
188188

189189
# 42| F
190+
191+
# 62| PrivateOverride1
192+
#-----| super -> Object
193+
194+
# 76| PrivateOverride2
195+
#-----| super -> PrivateOverride1

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,19 @@ getTarget
186186
| private.rb:43:3:44:5 | call to private | calls.rb:109:5:109:20 | private |
187187
| private.rb:51:3:51:19 | call to private | calls.rb:109:5:109:20 | private |
188188
| private.rb:53:3:53:9 | call to private | calls.rb:109:5:109:20 | private |
189+
| private.rb:63:3:65:5 | call to private | calls.rb:109:5:109:20 | private |
190+
| private.rb:64:7:64:32 | call to puts | calls.rb:102:5:102:30 | puts |
191+
| private.rb:67:3:69:5 | call to private | calls.rb:109:5:109:20 | private |
192+
| private.rb:68:7:68:32 | call to puts | calls.rb:102:5:102:30 | puts |
193+
| private.rb:72:7:72:8 | call to m1 | private.rb:63:11:65:5 | m1 |
194+
| private.rb:72:7:72:8 | call to m1 | private.rb:77:11:81:5 | m1 |
195+
| private.rb:77:3:81:5 | call to private | calls.rb:109:5:109:20 | private |
196+
| private.rb:78:7:78:32 | call to puts | calls.rb:102:5:102:30 | puts |
197+
| private.rb:79:7:79:8 | call to m2 | private.rb:67:11:69:5 | m2 |
198+
| private.rb:80:7:80:26 | call to new | calls.rb:114:5:114:16 | new |
199+
| private.rb:84:1:84:20 | call to new | calls.rb:114:5:114:16 | new |
200+
| private.rb:84:1:84:28 | call to call_m1 | private.rb:71:3:73:5 | call_m1 |
201+
| private.rb:85:1:85:20 | call to new | calls.rb:114:5:114:16 | new |
189202
unresolvedCall
190203
| calls.rb:26:9:26:18 | call to instance_m |
191204
| calls.rb:29:5:29:14 | call to instance_m |
@@ -230,6 +243,8 @@ unresolvedCall
230243
| private.rb:35:1:35:14 | call to private2 |
231244
| private.rb:36:1:36:14 | call to private3 |
232245
| private.rb:37:1:37:14 | call to private4 |
246+
| private.rb:80:7:80:29 | call to m1 |
247+
| private.rb:85:1:85:23 | call to m1 |
233248
privateMethod
234249
| calls.rb:1:1:3:3 | foo |
235250
| calls.rb:39:1:41:3 | call_instance_m |
@@ -253,3 +268,6 @@ privateMethod
253268
| private.rb:49:3:50:5 | private2 |
254269
| private.rb:55:3:56:5 | private3 |
255270
| private.rb:58:3:59:5 | private4 |
271+
| private.rb:63:11:65:5 | m1 |
272+
| private.rb:67:11:69:5 | m2 |
273+
| private.rb:77:11:81:5 | m1 |

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,20 @@ getMethod
4646
| modules.rb:5:3:14:5 | Foo::Bar | method_in_foo_bar | modules.rb:9:5:10:7 | method_in_foo_bar |
4747
| modules.rb:37:1:46:3 | Bar | method_a | modules.rb:38:3:39:5 | method_a |
4848
| modules.rb:37:1:46:3 | Bar | method_b | modules.rb:41:3:42:5 | method_b |
49+
| private.rb:1:1:29:3 | E | private1 | private.rb:2:11:3:5 | private1 |
4950
| private.rb:1:1:29:3 | E | private2 | private.rb:8:3:9:5 | private2 |
5051
| private.rb:1:1:29:3 | E | private3 | private.rb:14:3:15:5 | private3 |
5152
| private.rb:1:1:29:3 | E | private4 | private.rb:17:3:18:5 | private4 |
5253
| private.rb:1:1:29:3 | E | public | private.rb:5:3:6:5 | public |
54+
| private.rb:42:1:60:3 | F | private1 | private.rb:43:11:44:5 | private1 |
5355
| private.rb:42:1:60:3 | F | private2 | private.rb:49:3:50:5 | private2 |
5456
| private.rb:42:1:60:3 | F | private3 | private.rb:55:3:56:5 | private3 |
5557
| private.rb:42:1:60:3 | F | private4 | private.rb:58:3:59:5 | private4 |
5658
| private.rb:42:1:60:3 | F | public | private.rb:46:3:47:5 | public |
59+
| private.rb:62:1:74:3 | PrivateOverride1 | call_m1 | private.rb:71:3:73:5 | call_m1 |
60+
| private.rb:62:1:74:3 | PrivateOverride1 | m1 | private.rb:63:11:65:5 | m1 |
61+
| private.rb:62:1:74:3 | PrivateOverride1 | m2 | private.rb:67:11:69:5 | m2 |
62+
| private.rb:76:1:82:3 | PrivateOverride2 | m1 | private.rb:77:11:81:5 | m1 |
5763
lookupMethod
5864
| calls.rb:21:1:34:3 | M | instance_m | calls.rb:22:5:24:7 | instance_m |
5965
| calls.rb:43:1:58:3 | C | add_singleton | calls.rb:364:1:368:3 | add_singleton |
@@ -405,17 +411,33 @@ lookupMethod
405411
| modules_rec.rb:4:1:5:3 | A::B | puts | calls.rb:102:5:102:30 | puts |
406412
| modules_rec.rb:4:1:5:3 | A::B | to_s | calls.rb:169:5:170:7 | to_s |
407413
| private.rb:1:1:29:3 | E | new | calls.rb:114:5:114:16 | new |
414+
| private.rb:1:1:29:3 | E | private1 | private.rb:2:11:3:5 | private1 |
408415
| private.rb:1:1:29:3 | E | private2 | private.rb:8:3:9:5 | private2 |
409416
| private.rb:1:1:29:3 | E | private3 | private.rb:14:3:15:5 | private3 |
410417
| private.rb:1:1:29:3 | E | private4 | private.rb:17:3:18:5 | private4 |
411418
| private.rb:1:1:29:3 | E | private_on_main | private.rb:31:1:32:3 | private_on_main |
412419
| private.rb:1:1:29:3 | E | public | private.rb:5:3:6:5 | public |
413420
| private.rb:1:1:29:3 | E | puts | calls.rb:102:5:102:30 | puts |
414421
| private.rb:1:1:29:3 | E | to_s | calls.rb:169:5:170:7 | to_s |
422+
| private.rb:42:1:60:3 | F | private1 | private.rb:43:11:44:5 | private1 |
415423
| private.rb:42:1:60:3 | F | private2 | private.rb:49:3:50:5 | private2 |
416424
| private.rb:42:1:60:3 | F | private3 | private.rb:55:3:56:5 | private3 |
417425
| private.rb:42:1:60:3 | F | private4 | private.rb:58:3:59:5 | private4 |
418426
| private.rb:42:1:60:3 | F | public | private.rb:46:3:47:5 | public |
427+
| private.rb:62:1:74:3 | PrivateOverride1 | call_m1 | private.rb:71:3:73:5 | call_m1 |
428+
| private.rb:62:1:74:3 | PrivateOverride1 | m1 | private.rb:63:11:65:5 | m1 |
429+
| private.rb:62:1:74:3 | PrivateOverride1 | m2 | private.rb:67:11:69:5 | m2 |
430+
| private.rb:62:1:74:3 | PrivateOverride1 | new | calls.rb:114:5:114:16 | new |
431+
| private.rb:62:1:74:3 | PrivateOverride1 | private_on_main | private.rb:31:1:32:3 | private_on_main |
432+
| private.rb:62:1:74:3 | PrivateOverride1 | puts | calls.rb:102:5:102:30 | puts |
433+
| private.rb:62:1:74:3 | PrivateOverride1 | to_s | calls.rb:169:5:170:7 | to_s |
434+
| private.rb:76:1:82:3 | PrivateOverride2 | call_m1 | private.rb:71:3:73:5 | call_m1 |
435+
| private.rb:76:1:82:3 | PrivateOverride2 | m1 | private.rb:77:11:81:5 | m1 |
436+
| private.rb:76:1:82:3 | PrivateOverride2 | m2 | private.rb:67:11:69:5 | m2 |
437+
| private.rb:76:1:82:3 | PrivateOverride2 | new | calls.rb:114:5:114:16 | new |
438+
| private.rb:76:1:82:3 | PrivateOverride2 | private_on_main | private.rb:31:1:32:3 | private_on_main |
439+
| private.rb:76:1:82:3 | PrivateOverride2 | puts | calls.rb:102:5:102:30 | puts |
440+
| private.rb:76:1:82:3 | PrivateOverride2 | to_s | calls.rb:169:5:170:7 | to_s |
419441
enclosingMethod
420442
| calls.rb:2:5:2:14 | call to puts | calls.rb:1:1:3:3 | foo |
421443
| calls.rb:2:5:2:14 | self | calls.rb:1:1:3:3 | foo |
@@ -703,3 +725,22 @@ enclosingMethod
703725
| hello.rb:20:30:20:34 | self | hello.rb:19:5:21:7 | message |
704726
| hello.rb:20:38:20:40 | "!" | hello.rb:19:5:21:7 | message |
705727
| hello.rb:20:39:20:39 | ! | hello.rb:19:5:21:7 | message |
728+
| private.rb:64:7:64:32 | call to puts | private.rb:63:11:65:5 | m1 |
729+
| private.rb:64:7:64:32 | self | private.rb:63:11:65:5 | m1 |
730+
| private.rb:64:12:64:32 | "PrivateOverride1#m1" | private.rb:63:11:65:5 | m1 |
731+
| private.rb:64:13:64:31 | PrivateOverride1#m1 | private.rb:63:11:65:5 | m1 |
732+
| private.rb:68:7:68:32 | call to puts | private.rb:67:11:69:5 | m2 |
733+
| private.rb:68:7:68:32 | self | private.rb:67:11:69:5 | m2 |
734+
| private.rb:68:12:68:32 | "PrivateOverride1#m2" | private.rb:67:11:69:5 | m2 |
735+
| private.rb:68:13:68:31 | PrivateOverride1#m2 | private.rb:67:11:69:5 | m2 |
736+
| private.rb:72:7:72:8 | call to m1 | private.rb:71:3:73:5 | call_m1 |
737+
| private.rb:72:7:72:8 | self | private.rb:71:3:73:5 | call_m1 |
738+
| private.rb:78:7:78:32 | call to puts | private.rb:77:11:81:5 | m1 |
739+
| private.rb:78:7:78:32 | self | private.rb:77:11:81:5 | m1 |
740+
| private.rb:78:12:78:32 | "PrivateOverride2#m1" | private.rb:77:11:81:5 | m1 |
741+
| private.rb:78:13:78:31 | PrivateOverride2#m1 | private.rb:77:11:81:5 | m1 |
742+
| private.rb:79:7:79:8 | call to m2 | private.rb:77:11:81:5 | m1 |
743+
| private.rb:79:7:79:8 | self | private.rb:77:11:81:5 | m1 |
744+
| private.rb:80:7:80:22 | PrivateOverride1 | private.rb:77:11:81:5 | m1 |
745+
| private.rb:80:7:80:26 | call to new | private.rb:77:11:81:5 | m1 |
746+
| private.rb:80:7:80:29 | call to m1 | private.rb:77:11:81:5 | m1 |

0 commit comments

Comments
 (0)