Skip to content

Commit 299339f

Browse files
committed
Ruby: Expose relevant predicates from internal/Module.qll and make sure they are cached
1 parent 6e1914a commit 299339f

File tree

13 files changed

+36
-22
lines changed

13 files changed

+36
-22
lines changed

ruby/ql/lib/codeql/ruby/ApiGraphs.qll

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ private import codeql.ruby.AST
1010
private import codeql.ruby.DataFlow
1111
private import codeql.ruby.typetracking.TypeTracker
1212
private import codeql.ruby.typetracking.TypeTrackerSpecific as TypeTrackerSpecific
13-
private import codeql.ruby.ast.internal.Module
1413
private import codeql.ruby.controlflow.CfgNodes
1514
private import codeql.ruby.dataflow.internal.DataFlowPrivate as DataFlowPrivate
1615
private import codeql.ruby.dataflow.internal.DataFlowDispatch as DataFlowDispatch
@@ -482,7 +481,7 @@ module API {
482481
MkDef(DataFlow::Node nd) { isDef(nd) }
483482

484483
private string resolveTopLevel(ConstantReadAccess read) {
485-
TResolved(result) = resolveConstantReadAccess(read) and
484+
result = read.getModule().getQualifiedName() and
486485
not result.matches("%::%")
487486
}
488487

@@ -706,7 +705,7 @@ module API {
706705
exists(ClassDeclaration c, DataFlow::Node a, DataFlow::Node b |
707706
use(pred, a) and
708707
use(succ, b) and
709-
resolveConstant(b.asExpr().getExpr()) = resolveConstantWriteAccess(c) and
708+
b.asExpr().getExpr().(ConstantReadAccess).getAQualifiedName() = c.getAQualifiedName() and
710709
pragma[only_bind_into](c).getSuperclassExpr() = a.asExpr().getExpr() and
711710
lbl = Label::subclass()
712711
)

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,15 @@ class ConstantReadAccess extends ConstantAccess {
293293
*/
294294
Expr getValue() { result = getConstantReadAccessValue(this) }
295295

296+
/**
297+
* Gets a fully qualified name for this constant read, based on the context in
298+
* which it occurs.
299+
*/
300+
string getAQualifiedName() { result = resolveConstant(this) }
301+
302+
/** Gets the module that this read access resolves to, if any. */
303+
Module getModule() { result = resolveConstantReadAccess(this) }
304+
296305
final override string getAPrimaryQlClass() { result = "ConstantReadAccess" }
297306
}
298307

@@ -354,7 +363,7 @@ class ConstantWriteAccess extends ConstantAccess {
354363
* constants up the namespace chain, the fully qualified name of a nested
355364
* constant can be ambiguous from just statically looking at the AST.
356365
*/
357-
string getAQualifiedName() { result = resolveConstantWriteAccess(this) }
366+
string getAQualifiedName() { result = resolveConstantWrite(this) }
358367

359368
/**
360369
* Gets a qualified name for this constant. Deprecated in favor of

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ class Module extends TModule {
3434
exists(Namespace n | this = TUnresolved(n) and result = "...::" + n.toString())
3535
}
3636

37+
/**
38+
* Gets the qualified name of this module, if any.
39+
*
40+
* Only modules that can be resolved will have a qualified name.
41+
*/
42+
final string getQualifiedName() { this = TResolved(result) }
43+
3744
/** Gets the location of this module. */
3845
Location getLocation() {
3946
exists(Namespace n | this = TUnresolved(n) and result = n.getLocation())

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,9 @@ private module Cached {
135135
)
136136
}
137137

138+
cached
139+
string resolveConstantWrite(ConstantWriteAccess c) { result = resolveConstantWriteAccess(c) }
140+
138141
cached
139142
Method lookupMethod(Module m, string name) { TMethod(result) = lookupMethodOrConst(m, name) }
140143

@@ -472,7 +475,7 @@ private module ResolveImpl {
472475
}
473476
}
474477

475-
import ResolveImpl
478+
private import ResolveImpl
476479

477480
/**
478481
* A variant of AstNode::getEnclosingModule that excludes

ruby/ql/lib/codeql/ruby/frameworks/ActionController.qll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ private import codeql.ruby.Concepts
77
private import codeql.ruby.controlflow.CfgNodes
88
private import codeql.ruby.DataFlow
99
private import codeql.ruby.dataflow.RemoteFlowSources
10-
private import codeql.ruby.ast.internal.Module
1110
private import codeql.ruby.ApiGraphs
1211
private import ActionView
1312
private import codeql.ruby.frameworks.ActionDispatch
@@ -101,7 +100,7 @@ private predicate isRoute(
101100
ActionDispatch::Routing::Route route, string name, ActionControllerControllerClass controllerClass
102101
) {
103102
route.getController() + "_controller" =
104-
ActionDispatch::Routing::underscore(namespaceDeclaration(controllerClass)) and
103+
ActionDispatch::Routing::underscore(controllerClass.getAQualifiedName()) and
105104
name = route.getAction()
106105
}
107106

ruby/ql/lib/codeql/ruby/frameworks/ActionView.qll

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ private import codeql.ruby.Concepts
88
private import codeql.ruby.controlflow.CfgNodes
99
private import codeql.ruby.DataFlow
1010
private import codeql.ruby.dataflow.RemoteFlowSources
11-
private import codeql.ruby.ast.internal.Module
1211
private import ActionController
1312

1413
/**

ruby/ql/lib/codeql/ruby/frameworks/ActiveRecord.qll

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ private import codeql.ruby.controlflow.CfgNodes
88
private import codeql.ruby.DataFlow
99
private import codeql.ruby.dataflow.internal.DataFlowDispatch
1010
private import codeql.ruby.dataflow.internal.DataFlowPrivate
11-
private import codeql.ruby.ast.internal.Module
1211
private import codeql.ruby.ApiGraphs
1312
private import codeql.ruby.frameworks.Stdlib
1413
private import codeql.ruby.frameworks.Core
@@ -95,7 +94,7 @@ class ActiveRecordModelClassMethodCall extends MethodCall {
9594

9695
ActiveRecordModelClassMethodCall() {
9796
// e.g. Foo.where(...)
98-
recvCls.getModule() = resolveConstantReadAccess(this.getReceiver())
97+
recvCls.getModule() = this.getReceiver().(ConstantReadAccess).getModule()
9998
or
10099
// e.g. Foo.joins(:bars).where(...)
101100
recvCls = this.getReceiver().(ActiveRecordModelClassMethodCall).getReceiverClass()
@@ -282,7 +281,7 @@ private class ActiveRecordModelFinderCall extends ActiveRecordModelInstantiation
282281
recv = getUltimateReceiver(call) and
283282
(
284283
// The receiver refers to an `ActiveRecordModelClass` by name
285-
resolveConstant(recv) = cls.getAQualifiedName()
284+
recv.(ConstantReadAccess).getAQualifiedName() = cls.getAQualifiedName()
286285
or
287286
// The receiver is self, and the call is within a singleton method of
288287
// the `ActiveRecordModelClass`

ruby/ql/lib/codeql/ruby/frameworks/ActiveResource.qll

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
private import codeql.ruby.AST
77
private import codeql.ruby.Concepts
88
private import codeql.ruby.controlflow.CfgNodes
9-
private import codeql.ruby.ast.internal.Module
109
private import codeql.ruby.DataFlow
1110
private import codeql.ruby.ApiGraphs
1211

ruby/ql/lib/codeql/ruby/frameworks/GraphQL.qll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ private import codeql.ruby.Concepts
77
private import codeql.ruby.controlflow.CfgNodes
88
private import codeql.ruby.DataFlow
99
private import codeql.ruby.dataflow.RemoteFlowSources
10-
private import codeql.ruby.ast.internal.Module
1110
private import codeql.ruby.ApiGraphs
1211

1312
private API::Node graphQlSchema() { result = API::getTopLevelMember("GraphQL").getMember("Schema") }
@@ -233,7 +232,7 @@ private class GraphqlSchemaObjectClassMethodCall extends MethodCall {
233232

234233
GraphqlSchemaObjectClassMethodCall() {
235234
// e.g. Foo.some_method(...)
236-
recvCls.getModule() = resolveConstantReadAccess(this.getReceiver())
235+
recvCls.getModule() = this.getReceiver().(ConstantReadAccess).getModule()
237236
or
238237
// e.g. self.some_method(...) within a graphql Object or Interface
239238
this.getReceiver() instanceof SelfVariableAccess and

ruby/ql/lib/codeql/ruby/frameworks/Rails.qll

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ private import codeql.ruby.frameworks.ActionController
99
private import codeql.ruby.frameworks.ActionView
1010
private import codeql.ruby.frameworks.ActiveRecord
1111
private import codeql.ruby.frameworks.ActiveStorage
12-
private import codeql.ruby.ast.internal.Module
1312
private import codeql.ruby.ApiGraphs
1413
private import codeql.ruby.security.OpenSSL
1514

@@ -29,7 +28,7 @@ private class RailtieClass extends ClassDeclaration {
2928
RailtieClass() {
3029
this.getSuperclassExpr() instanceof RailtieClassAccess or
3130
exists(RailtieClass other |
32-
other.getModule() = resolveConstantReadAccess(this.getSuperclassExpr())
31+
other.getModule() = this.getSuperclassExpr().(ConstantReadAccess).getModule()
3332
)
3433
}
3534
}
@@ -41,7 +40,7 @@ private DataFlow::CallNode getAConfigureCallNode() {
4140
// `Rails::Application.configure`
4241
exists(ConstantReadAccess read, RailtieClass cls |
4342
read = result.getReceiver().asExpr().getExpr() and
44-
resolveConstantReadAccess(read) = cls.getModule() and
43+
read.getModule() = cls.getModule() and
4544
result.asExpr().getExpr().(MethodCall).getMethodName() = "configure"
4645
)
4746
}

0 commit comments

Comments
 (0)