Skip to content

Commit a213e9e

Browse files
authored
Merge pull request #1 from hvitved/rb/data-flow-layer-capture2
Ruby: Make sure to always generate SSA definitions for namespace self-variables
2 parents f991991 + 2737255 commit a213e9e

File tree

4 files changed

+26
-42
lines changed

4 files changed

+26
-42
lines changed

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

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -262,9 +262,6 @@ 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
268265
TNormalParameterNode(Parameter p) {
269266
p instanceof SimpleParameter or
270267
p instanceof OptionalParameter or
@@ -405,8 +402,6 @@ private module Cached {
405402
or
406403
// Needed for stores in type tracking
407404
TypeTrackerSpecific::storeStepIntoSourceNode(_, n, _)
408-
or
409-
n instanceof TRawNamespaceSelf
410405
}
411406

412407
cached
@@ -528,38 +523,6 @@ class SsaSelfDefinitionNode extends LocalSourceNode, SsaDefinitionNode {
528523
Scope getSelfScope() { result = self.getDeclaringScope() }
529524
}
530525

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-
563526
/**
564527
* A value returning statement, viewed as a node in a data flow graph.
565528
*

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -370,9 +370,11 @@ private module Cached {
370370
LocalSourceNode getConstantAccessNode(ConstantAccess access) {
371371
// Namespaces don't evaluate to the constant being accessed, they return the value of their last statement.
372372
// Use the definition of 'self' in the namespace as the representative in this case.
373-
if access instanceof Namespace
374-
then result = getNamespaceSelf(access)
375-
else result.asExpr().getExpr() = access
373+
result.(SsaDefinitionNode).getDefinition().(Ssa::SelfDefinition).getSourceVariable() =
374+
access.(Namespace).getModuleSelfVariable()
375+
or
376+
not access instanceof Namespace and
377+
result.asExpr().getExpr() = access
376378
}
377379

378380
cached

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
private import codeql.ssa.Ssa as SsaImplCommon
22
private import codeql.ruby.AST
33
private import codeql.ruby.CFG as Cfg
4+
private import codeql.ruby.controlflow.internal.ControlFlowGraphImplShared as ControlFlowGraphImplShared
45
private import codeql.ruby.ast.Variable
56
private import Cfg::CfgNodes::ExprNodes
67

@@ -53,6 +54,9 @@ private module SsaInput implements SsaImplCommon::InputSig {
5354
or
5455
capturedExitRead(bb, i, v) and
5556
certain = false
57+
or
58+
namespaceSelfExitRead(bb, i, v) and
59+
certain = false
5660
}
5761
}
5862

@@ -94,6 +98,21 @@ private predicate capturedExitRead(Cfg::AnnotatedExitBasicBlock bb, int i, Local
9498
i = bb.length()
9599
}
96100

101+
/**
102+
* Holds if a pseudo read of namespace self-variable `v` should be inserted
103+
* at index `i` in basic block `bb`. We do this to ensure that namespace
104+
* self-variables always get an SSA definition.
105+
*/
106+
private predicate namespaceSelfExitRead(Cfg::AnnotatedExitBasicBlock bb, int i, SelfVariable v) {
107+
exists(Namespace ns, AstNode last |
108+
v.getDeclaringScope() = ns and
109+
last = ControlFlowGraphImplShared::getAControlFlowExitNode(ns) and
110+
if last = ns
111+
then bb.getNode(i).getAPredecessor().getNode() = last
112+
else bb.getNode(i).getNode() = last
113+
)
114+
}
115+
97116
/**
98117
* Holds if captured variable `v` is read directly inside `scope`,
99118
* or inside a (transitively) nested scope of `scope`.

ruby/ql/test/library-tests/dataflow/type-tracker/TypeTracker.expected

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
track
2-
| type_tracker.rb:1:1:10:3 | Container | type tracker without call steps | type_tracker.rb:1:1:10:3 | Container |
2+
| type_tracker.rb:1:1:10:3 | self (Container) | type tracker without call steps | type_tracker.rb:1:1:10:3 | self (Container) |
33
| type_tracker.rb:1:1:10:3 | self (type_tracker.rb) | type tracker with call steps | type_tracker.rb:18:1:21:3 | self (positional) |
44
| type_tracker.rb:1:1:10:3 | self (type_tracker.rb) | type tracker with call steps | type_tracker.rb:18:1:21:3 | self in positional |
55
| type_tracker.rb:1:1:10:3 | self (type_tracker.rb) | type tracker with call steps | type_tracker.rb:25:1:28:3 | self (keyword) |
@@ -357,7 +357,7 @@ track
357357
| type_tracker.rb:52:5:52:13 | ...[...] | type tracker without call steps | type_tracker.rb:34:1:53:3 | return return in throughArray |
358358
| type_tracker.rb:52:5:52:13 | ...[...] | type tracker without call steps | type_tracker.rb:52:5:52:13 | ...[...] |
359359
trackEnd
360-
| type_tracker.rb:1:1:10:3 | Container | type_tracker.rb:1:1:10:3 | Container |
360+
| type_tracker.rb:1:1:10:3 | self (Container) | type_tracker.rb:1:1:10:3 | self (Container) |
361361
| type_tracker.rb:1:1:10:3 | self (type_tracker.rb) | type_tracker.rb:1:1:10:3 | self (type_tracker.rb) |
362362
| type_tracker.rb:1:1:10:3 | self (type_tracker.rb) | type_tracker.rb:18:1:21:3 | self (positional) |
363363
| type_tracker.rb:1:1:10:3 | self (type_tracker.rb) | type_tracker.rb:18:1:21:3 | self in positional |

0 commit comments

Comments
 (0)