Skip to content

Commit ab4e341

Browse files
committed
Ruby: fix handling of namespaces with no 'self'
1 parent 9da5ec7 commit ab4e341

File tree

2 files changed

+38
-3
lines changed

2 files changed

+38
-3
lines changed

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,9 @@ private module Cached {
262262
)
263263
} or
264264
TSsaDefinitionNode(Ssa::Definition def) or
265+
TRawNamespaceSelf(Namespace ns) {
266+
not exists(Ssa::SelfDefinition def | def.getSourceVariable() = ns.getModuleSelfVariable())
267+
} or
265268
TNormalParameterNode(Parameter p) {
266269
p instanceof SimpleParameter or
267270
p instanceof OptionalParameter or
@@ -402,6 +405,8 @@ private module Cached {
402405
or
403406
// Needed for stores in type tracking
404407
TypeTrackerSpecific::storeStepIntoSourceNode(_, n, _)
408+
or
409+
n instanceof TRawNamespaceSelf
405410
}
406411

407412
cached
@@ -523,6 +528,38 @@ class SsaSelfDefinitionNode extends LocalSourceNode, SsaDefinitionNode {
523528
Scope getSelfScope() { result = self.getDeclaringScope() }
524529
}
525530

531+
/**
532+
* A representative for the created or re-opened class/module in a `Namespace` that does
533+
* not have an SSA definition for `self`.
534+
*/
535+
class RawNamespaceSelf extends NodeImpl, TRawNamespaceSelf {
536+
private Namespace namespace;
537+
538+
RawNamespaceSelf() { this = TRawNamespaceSelf(namespace) }
539+
540+
/** Gets the namespace for which this represents the created or re-opened class/module. */
541+
Namespace getNamespace() { result = namespace }
542+
543+
override CfgScope getCfgScope() { result = namespace.getCfgScope() }
544+
545+
override Location getLocationImpl() { result = namespace.getLocation() }
546+
547+
override string toStringImpl() { result = namespace.toString() }
548+
}
549+
550+
/**
551+
* Gets a representative for the created or re-opened class/module in a `Namespace`.
552+
*
553+
* This is usually the SSA definition for `self`, but if this node does not exist due to lack of liveness,
554+
* it is the `RawNamespaceSelf` node.
555+
*/
556+
LocalSourceNode getNamespaceSelf(Namespace namespace) {
557+
result.(SsaDefinitionNode).getDefinition().(Ssa::SelfDefinition).getSourceVariable() =
558+
namespace.getModuleSelfVariable()
559+
or
560+
result = TRawNamespaceSelf(namespace)
561+
}
562+
526563
/**
527564
* A value returning statement, viewed as a node in a data flow graph.
528565
*

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,9 +1113,7 @@ private LocalSourceNode getConstantAccessNode(ConstantAccess access) {
11131113
// Namespaces don't evaluate to the constant being accessed, they return the value of their last statement.
11141114
// Use the definition of 'self' in the namespace as the representative in this case.
11151115
if access instanceof Namespace
1116-
then
1117-
result.(SsaDefinitionNode).getDefinition().(Ssa::SelfDefinition).getSourceVariable() =
1118-
access.(Namespace).getModuleSelfVariable()
1116+
then result = getNamespaceSelf(access)
11191117
else result.asExpr().getExpr() = access
11201118
}
11211119

0 commit comments

Comments
 (0)