Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ private module Cached {
// ```
exists(DataFlow::Node sourceNode, Module m |
flowsToMethodCall(call, sourceNode, method) and
singletonMethodOnModule(result, method, m)
result = lookupSingletonMethod(m, method)
|
// ```rb
// def C.singleton; end # <- result
Expand Down Expand Up @@ -725,14 +725,37 @@ private predicate singletonMethodOnModule(MethodBase method, string name, Module
selfInModule(object.(SelfVariableReadAccess).getVariable(), m)
)
or
flowsToSingletonMethodObject(trackModuleAccess(m), method, name)
exists(DataFlow::LocalSourceNode sourceNode |
m = resolveConstantReadAccess(sourceNode.asExpr().getExpr()) and
flowsToSingletonMethodObject(sourceNode, method, name)
)
or
exists(Module other |
extendCallModule(m, other) and
method = lookupMethod(other, name)
)
}

/**
* Holds if `method` is a singleton method named `name`, defined on module
* `m`, or any transitive base class of `m`.
*/
pragma[nomagic]
private MethodBase lookupSingletonMethod(Module m, string name) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add some QLDoc indicating that this takes inheritance into account, and likewise on singletonMethodOnModule.

I'd probably have named these predicates in a way that clarifies their relationship, such as:

  • lookupOwnSingletonMethod
  • lookupSingletonMethod

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I simply used the naming after the existing lookupMethod predicate for instance methods. I'll add ql doc.

singletonMethodOnModule(result, name, m)
or
// cannot be part of `singletonMethodOnModule` because it would introduce
// negative recursion below
exists(DataFlow::LocalSourceNode sourceNode |
sourceNode = trackModuleAccess(m) and
not m = resolveConstantReadAccess(sourceNode.asExpr().getExpr()) and
flowsToSingletonMethodObject(sourceNode, result, name)
)
or
not singletonMethodOnModule(_, name, m) and
result = lookupSingletonMethod(m.getSuperClass(), name)
}

/**
* Holds if `method` is a singleton method named `name`, defined on expression
* `object`, where `object` is not likely to resolve to a module:
Expand Down
16 changes: 8 additions & 8 deletions ruby/ql/test/library-tests/modules/ancestors.expected
Original file line number Diff line number Diff line change
Expand Up @@ -89,25 +89,25 @@ calls.rb:
# 377| SingletonOverride1
#-----| super -> Object

# 402| SingletonOverride2
# 404| SingletonOverride2
#-----| super -> SingletonOverride1

# 417| ConditionalInstanceMethods
# 421| ConditionalInstanceMethods
#-----| super -> Object

# 480| ExtendSingletonMethod
# 484| ExtendSingletonMethod

# 490| ExtendSingletonMethod2
# 494| ExtendSingletonMethod2

# 496| ExtendSingletonMethod3
# 500| ExtendSingletonMethod3

# 509| ProtectedMethodInModule
# 513| ProtectedMethodInModule

# 515| ProtectedMethods
# 519| ProtectedMethods
#-----| super -> Object
#-----| include -> ProtectedMethodInModule

# 534| ProtectedMethodsSub
# 538| ProtectedMethodsSub
#-----| super -> ProtectedMethods

hello.rb:
Expand Down
222 changes: 113 additions & 109 deletions ruby/ql/test/library-tests/modules/callgraph.expected
Original file line number Diff line number Diff line change
Expand Up @@ -148,67 +148,73 @@ getTarget
| calls.rb:375:1:375:11 | call to instance | calls.rb:368:5:370:7 | instance |
| calls.rb:380:13:380:48 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:384:13:384:22 | call to singleton1 | calls.rb:379:9:381:11 | singleton1 |
| calls.rb:384:13:384:22 | call to singleton1 | calls.rb:404:9:406:11 | singleton1 |
| calls.rb:384:13:384:22 | call to singleton1 | calls.rb:406:9:408:11 | singleton1 |
| calls.rb:389:9:389:44 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:393:9:393:18 | call to singleton2 | calls.rb:388:5:390:7 | singleton2 |
| calls.rb:393:9:393:18 | call to singleton2 | calls.rb:409:5:411:7 | singleton2 |
| calls.rb:393:9:393:18 | call to singleton2 | calls.rb:411:5:413:7 | singleton2 |
| calls.rb:396:5:396:14 | call to singleton2 | calls.rb:388:5:390:7 | singleton2 |
| calls.rb:399:1:399:34 | call to call_singleton1 | calls.rb:383:9:385:11 | call_singleton1 |
| calls.rb:400:1:400:34 | call to call_singleton2 | calls.rb:392:5:394:7 | call_singleton2 |
| calls.rb:405:13:405:48 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:410:9:410:44 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:420:13:420:48 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:425:9:425:44 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:428:13:428:48 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:431:17:431:52 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:439:9:443:11 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:439:9:443:15 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:441:17:441:40 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:447:1:447:30 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:447:1:447:33 | call to m1 | calls.rb:419:9:421:11 | m1 |
| calls.rb:448:1:448:30 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:449:1:449:30 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:449:1:449:33 | call to m2 | calls.rb:424:5:436:7 | m2 |
| calls.rb:450:1:450:30 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:399:1:399:29 | call to singleton1 | calls.rb:379:9:381:11 | singleton1 |
| calls.rb:400:1:400:29 | call to singleton2 | calls.rb:388:5:390:7 | singleton2 |
| calls.rb:401:1:401:34 | call to call_singleton1 | calls.rb:383:9:385:11 | call_singleton1 |
| calls.rb:402:1:402:34 | call to call_singleton2 | calls.rb:392:5:394:7 | call_singleton2 |
| calls.rb:407:13:407:48 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:412:9:412:44 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:416:1:416:29 | call to singleton1 | calls.rb:406:9:408:11 | singleton1 |
| calls.rb:417:1:417:29 | call to singleton2 | calls.rb:411:5:413:7 | singleton2 |
| calls.rb:418:1:418:34 | call to call_singleton1 | calls.rb:383:9:385:11 | call_singleton1 |
| calls.rb:419:1:419:34 | call to call_singleton2 | calls.rb:392:5:394:7 | call_singleton2 |
| calls.rb:424:13:424:48 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:429:9:429:44 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:432:13:432:48 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:435:17:435:52 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:443:9:447:11 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:443:9:447:15 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:445:17:445:40 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:451:1:451:30 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:451:1:451:33 | call to m1 | calls.rb:423:9:425:11 | m1 |
| calls.rb:452:1:452:30 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:454:27:472:3 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:457:13:457:22 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:461:5:465:7 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:461:5:465:11 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:463:13:463:22 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:469:13:469:27 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:474:1:474:27 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:475:1:475:27 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:476:1:476:27 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:477:1:477:27 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:453:1:453:30 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:453:1:453:33 | call to m2 | calls.rb:428:5:440:7 | m2 |
| calls.rb:454:1:454:30 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:455:1:455:30 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:456:1:456:30 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:458:27:476:3 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:461:13:461:22 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:465:5:469:7 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:465:5:469:11 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:467:13:467:22 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:473:13:473:27 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:478:1:478:27 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:488:1:488:31 | call to singleton | calls.rb:481:5:483:7 | singleton |
| calls.rb:494:1:494:32 | call to singleton | calls.rb:481:5:483:7 | singleton |
| calls.rb:501:1:501:32 | call to singleton | calls.rb:481:5:483:7 | singleton |
| calls.rb:507:1:507:13 | call to singleton | calls.rb:481:5:483:7 | singleton |
| calls.rb:516:5:516:35 | call to include | calls.rb:108:5:110:7 | include |
| calls.rb:519:9:519:35 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:523:9:523:11 | call to foo | calls.rb:510:15:512:7 | foo |
| calls.rb:524:9:524:11 | call to bar | calls.rb:518:15:520:7 | bar |
| calls.rb:525:9:525:28 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:525:9:525:32 | call to foo | calls.rb:510:15:512:7 | foo |
| calls.rb:526:9:526:28 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:526:9:526:32 | call to bar | calls.rb:518:15:520:7 | bar |
| calls.rb:530:1:530:20 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:531:1:531:20 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:532:1:532:20 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:532:1:532:24 | call to baz | calls.rb:522:5:527:7 | baz |
| calls.rb:536:9:536:11 | call to foo | calls.rb:510:15:512:7 | foo |
| calls.rb:537:9:537:31 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:537:9:537:35 | call to foo | calls.rb:510:15:512:7 | foo |
| calls.rb:541:1:541:23 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:542:1:542:23 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:543:1:543:23 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:543:1:543:27 | call to baz | calls.rb:535:5:538:7 | baz |
| calls.rb:545:2:545:6 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:545:20:545:24 | call to baz | calls.rb:51:5:57:7 | baz |
| calls.rb:546:26:546:37 | call to capitalize | calls.rb:97:5:97:23 | capitalize |
| calls.rb:479:1:479:27 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:480:1:480:27 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:481:1:481:27 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:482:1:482:27 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:492:1:492:31 | call to singleton | calls.rb:485:5:487:7 | singleton |
| calls.rb:498:1:498:32 | call to singleton | calls.rb:485:5:487:7 | singleton |
| calls.rb:505:1:505:32 | call to singleton | calls.rb:485:5:487:7 | singleton |
| calls.rb:511:1:511:13 | call to singleton | calls.rb:485:5:487:7 | singleton |
| calls.rb:520:5:520:35 | call to include | calls.rb:108:5:110:7 | include |
| calls.rb:523:9:523:35 | call to puts | calls.rb:102:5:102:30 | puts |
| calls.rb:527:9:527:11 | call to foo | calls.rb:514:15:516:7 | foo |
| calls.rb:528:9:528:11 | call to bar | calls.rb:522:15:524:7 | bar |
| calls.rb:529:9:529:28 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:529:9:529:32 | call to foo | calls.rb:514:15:516:7 | foo |
| calls.rb:530:9:530:28 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:530:9:530:32 | call to bar | calls.rb:522:15:524:7 | bar |
| calls.rb:534:1:534:20 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:535:1:535:20 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:536:1:536:20 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:536:1:536:24 | call to baz | calls.rb:526:5:531:7 | baz |
| calls.rb:540:9:540:11 | call to foo | calls.rb:514:15:516:7 | foo |
| calls.rb:541:9:541:31 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:541:9:541:35 | call to foo | calls.rb:514:15:516:7 | foo |
| calls.rb:545:1:545:23 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:546:1:546:23 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:547:1:547:23 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:547:1:547:27 | call to baz | calls.rb:539:5:542:7 | baz |
| calls.rb:549:2:549:6 | call to new | calls.rb:117:5:117:16 | new |
| calls.rb:549:20:549:24 | call to baz | calls.rb:51:5:57:7 | baz |
| calls.rb:550:26:550:37 | call to capitalize | calls.rb:97:5:97:23 | capitalize |
| hello.rb:12:5:12:24 | call to include | calls.rb:108:5:110:7 | include |
| hello.rb:14:16:14:20 | call to hello | hello.rb:2:5:4:7 | hello |
| hello.rb:20:16:20:20 | call to super | hello.rb:13:5:15:7 | message |
Expand Down Expand Up @@ -286,46 +292,44 @@ unresolvedCall
| calls.rb:274:1:274:14 | call to singleton_g |
| calls.rb:276:1:276:14 | call to singleton_g |
| calls.rb:313:9:313:20 | call to instance |
| calls.rb:414:1:414:34 | call to call_singleton1 |
| calls.rb:415:1:415:34 | call to call_singleton2 |
| calls.rb:418:8:418:13 | call to rand |
| calls.rb:418:8:418:17 | ... > ... |
| calls.rb:435:9:435:10 | call to m3 |
| calls.rb:438:8:438:13 | call to rand |
| calls.rb:438:8:438:17 | ... > ... |
| calls.rb:439:9:443:18 | call to m5 |
| calls.rb:448:1:448:33 | call to m3 |
| calls.rb:450:1:450:33 | call to m3 |
| calls.rb:451:1:451:33 | call to m4 |
| calls.rb:452:1:452:33 | call to m5 |
| calls.rb:455:5:455:11 | call to [] |
| calls.rb:455:5:459:7 | call to each |
| calls.rb:461:5:465:15 | call to bar |
| calls.rb:467:5:467:11 | call to [] |
| calls.rb:467:5:471:7 | call to each |
| calls.rb:468:9:470:11 | call to define_method |
| calls.rb:474:1:474:31 | call to foo |
| calls.rb:475:1:475:31 | call to bar |
| calls.rb:476:1:476:33 | call to baz_0 |
| calls.rb:477:1:477:33 | call to baz_1 |
| calls.rb:478:1:478:33 | call to baz_2 |
| calls.rb:482:9:482:46 | call to puts |
| calls.rb:485:5:485:15 | call to extend |
| calls.rb:491:5:491:32 | call to extend |
| calls.rb:499:1:499:51 | call to extend |
| calls.rb:504:1:504:13 | call to singleton |
| calls.rb:505:1:505:32 | call to extend |
| calls.rb:510:5:512:7 | call to protected |
| calls.rb:511:9:511:42 | call to puts |
| calls.rb:518:5:520:7 | call to protected |
| calls.rb:530:1:530:24 | call to foo |
| calls.rb:531:1:531:24 | call to bar |
| calls.rb:541:1:541:27 | call to foo |
| calls.rb:542:1:542:27 | call to bar |
| calls.rb:545:1:545:7 | call to [] |
| calls.rb:545:1:545:26 | call to each |
| calls.rb:546:1:546:13 | call to [] |
| calls.rb:546:1:546:39 | call to each |
| calls.rb:422:8:422:13 | call to rand |
| calls.rb:422:8:422:17 | ... > ... |
| calls.rb:439:9:439:10 | call to m3 |
| calls.rb:442:8:442:13 | call to rand |
| calls.rb:442:8:442:17 | ... > ... |
| calls.rb:443:9:447:18 | call to m5 |
| calls.rb:452:1:452:33 | call to m3 |
| calls.rb:454:1:454:33 | call to m3 |
| calls.rb:455:1:455:33 | call to m4 |
| calls.rb:456:1:456:33 | call to m5 |
| calls.rb:459:5:459:11 | call to [] |
| calls.rb:459:5:463:7 | call to each |
| calls.rb:465:5:469:15 | call to bar |
| calls.rb:471:5:471:11 | call to [] |
| calls.rb:471:5:475:7 | call to each |
| calls.rb:472:9:474:11 | call to define_method |
| calls.rb:478:1:478:31 | call to foo |
| calls.rb:479:1:479:31 | call to bar |
| calls.rb:480:1:480:33 | call to baz_0 |
| calls.rb:481:1:481:33 | call to baz_1 |
| calls.rb:482:1:482:33 | call to baz_2 |
| calls.rb:486:9:486:46 | call to puts |
| calls.rb:489:5:489:15 | call to extend |
| calls.rb:495:5:495:32 | call to extend |
| calls.rb:503:1:503:51 | call to extend |
| calls.rb:508:1:508:13 | call to singleton |
| calls.rb:509:1:509:32 | call to extend |
| calls.rb:514:5:516:7 | call to protected |
| calls.rb:515:9:515:42 | call to puts |
| calls.rb:522:5:524:7 | call to protected |
| calls.rb:534:1:534:24 | call to foo |
| calls.rb:535:1:535:24 | call to bar |
| calls.rb:545:1:545:27 | call to foo |
| calls.rb:546:1:546:27 | call to bar |
| calls.rb:549:1:549:7 | call to [] |
| calls.rb:549:1:549:26 | call to each |
| calls.rb:550:1:550:13 | call to [] |
| calls.rb:550:1:550:39 | call to each |
| hello.rb:20:16:20:26 | ... + ... |
| hello.rb:20:16:20:34 | ... + ... |
| hello.rb:20:16:20:40 | ... + ... |
Expand All @@ -351,8 +355,8 @@ privateMethod
| calls.rb:278:1:286:3 | create |
| calls.rb:343:1:359:3 | pattern_dispatch |
| calls.rb:367:1:371:3 | add_singleton |
| calls.rb:456:9:458:11 | foo |
| calls.rb:462:9:464:11 | bar |
| calls.rb:460:9:462:11 | foo |
| calls.rb:466:9:468:11 | bar |
| private.rb:2:11:3:5 | private1 |
| private.rb:8:3:9:5 | private2 |
| private.rb:14:3:15:5 | private3 |
Expand Down Expand Up @@ -417,16 +421,16 @@ publicMethod
| calls.rb:383:9:385:11 | call_singleton1 |
| calls.rb:388:5:390:7 | singleton2 |
| calls.rb:392:5:394:7 | call_singleton2 |
| calls.rb:404:9:406:11 | singleton1 |
| calls.rb:409:5:411:7 | singleton2 |
| calls.rb:419:9:421:11 | m1 |
| calls.rb:424:5:436:7 | m2 |
| calls.rb:427:9:433:11 | m3 |
| calls.rb:430:13:432:15 | m4 |
| calls.rb:440:13:442:15 | m5 |
| calls.rb:481:5:483:7 | singleton |
| calls.rb:522:5:527:7 | baz |
| calls.rb:535:5:538:7 | baz |
| calls.rb:406:9:408:11 | singleton1 |
| calls.rb:411:5:413:7 | singleton2 |
| calls.rb:423:9:425:11 | m1 |
| calls.rb:428:5:440:7 | m2 |
| calls.rb:431:9:437:11 | m3 |
| calls.rb:434:13:436:15 | m4 |
| calls.rb:444:13:446:15 | m5 |
| calls.rb:485:5:487:7 | singleton |
| calls.rb:526:5:531:7 | baz |
| calls.rb:539:5:542:7 | baz |
| hello.rb:2:5:4:7 | hello |
| hello.rb:5:5:7:7 | world |
| hello.rb:13:5:15:7 | message |
Expand All @@ -443,7 +447,7 @@ publicMethod
| private.rb:66:3:67:5 | public |
| private.rb:91:3:93:5 | call_m1 |
protectedMethod
| calls.rb:510:15:512:7 | foo |
| calls.rb:518:15:520:7 | bar |
| calls.rb:514:15:516:7 | foo |
| calls.rb:522:15:524:7 | bar |
| private.rb:32:3:33:5 | protected1 |
| private.rb:35:3:36:5 | protected2 |
4 changes: 4 additions & 0 deletions ruby/ql/test/library-tests/modules/calls.rb
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,8 @@ def self.call_singleton2
singleton2
end

SingletonOverride1.singleton1
SingletonOverride1.singleton2
SingletonOverride1.call_singleton1
SingletonOverride1.call_singleton2

Expand All @@ -411,6 +413,8 @@ def self.singleton2
end
end

SingletonOverride2.singleton1
SingletonOverride2.singleton2
SingletonOverride2.call_singleton1
SingletonOverride2.call_singleton2

Expand Down
Loading