mirror of
https://github.com/github/codeql.git
synced 2026-05-03 04:39:29 +02:00
Ruby: Add tests for phi reads
This commit is contained in:
@@ -2,6 +2,7 @@ private import codeql.ssa.Ssa as SsaImplCommon
|
||||
private import codeql.ruby.AST
|
||||
private import codeql.ruby.CFG as Cfg
|
||||
private import codeql.ruby.controlflow.internal.ControlFlowGraphImplShared as ControlFlowGraphImplShared
|
||||
private import codeql.ruby.dataflow.SSA
|
||||
private import codeql.ruby.ast.Variable
|
||||
private import Cfg::CfgNodes::ExprNodes
|
||||
|
||||
@@ -61,7 +62,23 @@ private module SsaInput implements SsaImplCommon::InputSig {
|
||||
}
|
||||
}
|
||||
|
||||
import SsaImplCommon::Make<SsaInput>
|
||||
private import SsaImplCommon::Make<SsaInput> as Impl
|
||||
|
||||
class Definition = Impl::Definition;
|
||||
|
||||
class WriteDefinition = Impl::WriteDefinition;
|
||||
|
||||
class UncertainWriteDefinition = Impl::UncertainWriteDefinition;
|
||||
|
||||
class PhiNode = Impl::PhiNode;
|
||||
|
||||
module Consistency = Impl::Consistency;
|
||||
|
||||
module ExposedForTestingOnly {
|
||||
predicate ssaDefReachesReadExt = Impl::ssaDefReachesReadExt/4;
|
||||
|
||||
predicate phiHasInputFromBlockExt = Impl::phiHasInputFromBlockExt/3;
|
||||
}
|
||||
|
||||
/** Holds if `v` is uninitialized at index `i` in entry block `bb`. */
|
||||
predicate uninitializedWrite(Cfg::EntryBasicBlock bb, int i, LocalVariable v) {
|
||||
@@ -204,7 +221,7 @@ private predicate adjacentDefRead(
|
||||
Definition def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2,
|
||||
SsaInput::SourceVariable v
|
||||
) {
|
||||
adjacentDefRead(def, bb1, i1, bb2, i2) and
|
||||
Impl::adjacentDefRead(def, bb1, i1, bb2, i2) and
|
||||
v = def.getSourceVariable()
|
||||
}
|
||||
|
||||
@@ -220,7 +237,7 @@ private predicate adjacentDefReachesRead(
|
||||
exists(SsaInput::BasicBlock bb3, int i3 |
|
||||
adjacentDefReachesRead(def, bb1, i1, bb3, i3) and
|
||||
SsaInput::variableRead(bb3, i3, _, false) and
|
||||
adjacentDefRead(def, bb3, i3, bb2, i2)
|
||||
Impl::adjacentDefRead(def, bb3, i3, bb2, i2)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -243,11 +260,11 @@ private predicate adjacentDefReachesUncertainRead(
|
||||
/** Same as `lastRefRedef`, but skips uncertain reads. */
|
||||
pragma[nomagic]
|
||||
private predicate lastRefSkipUncertainReads(Definition def, SsaInput::BasicBlock bb, int i) {
|
||||
lastRef(def, bb, i) and
|
||||
Impl::lastRef(def, bb, i) and
|
||||
not SsaInput::variableRead(bb, i, def.getSourceVariable(), false)
|
||||
or
|
||||
exists(SsaInput::BasicBlock bb0, int i0 |
|
||||
lastRef(def, bb0, i0) and
|
||||
Impl::lastRef(def, bb0, i0) and
|
||||
adjacentDefReachesUncertainRead(def, bb, i, bb0, i0)
|
||||
)
|
||||
}
|
||||
@@ -304,7 +321,7 @@ private module Cached {
|
||||
cached
|
||||
VariableReadAccessCfgNode getARead(Definition def) {
|
||||
exists(LocalVariable v, Cfg::BasicBlock bb, int i |
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
Impl::ssaDefReachesRead(v, def, bb, i) and
|
||||
variableReadActual(bb, i, v) and
|
||||
result = bb.getNode(i)
|
||||
)
|
||||
@@ -315,7 +332,7 @@ private module Cached {
|
||||
Definition def, CallCfgNode call, LocalVariable v, Cfg::CfgScope scope
|
||||
) {
|
||||
exists(Cfg::BasicBlock bb, int i |
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
Impl::ssaDefReachesRead(v, def, bb, i) and
|
||||
capturedCallRead(call, bb, i, v) and
|
||||
scope.getOuterCfgScope() = bb.getScope()
|
||||
)
|
||||
@@ -360,7 +377,7 @@ private module Cached {
|
||||
Definition def, LocalVariable v, Cfg::CfgScope scope
|
||||
) {
|
||||
exists(Cfg::BasicBlock bb, int i |
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
Impl::ssaDefReachesRead(v, def, bb, i) and
|
||||
capturedExitRead(bb, i, v) and
|
||||
scope = bb.getScope().getOuterCfgScope*()
|
||||
)
|
||||
@@ -403,7 +420,7 @@ private module Cached {
|
||||
|
||||
cached
|
||||
Definition phiHasInputFromBlock(PhiNode phi, Cfg::BasicBlock bb) {
|
||||
phiHasInputFromBlock(phi, result, bb)
|
||||
Impl::phiHasInputFromBlock(phi, result, bb)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -459,19 +476,45 @@ private module Cached {
|
||||
*/
|
||||
cached
|
||||
predicate lastRefBeforeRedef(Definition def, Cfg::BasicBlock bb, int i, Definition next) {
|
||||
lastRefRedef(def, bb, i, next) and
|
||||
Impl::lastRefRedef(def, bb, i, next) and
|
||||
not SsaInput::variableRead(bb, i, def.getSourceVariable(), false)
|
||||
or
|
||||
exists(SsaInput::BasicBlock bb0, int i0 |
|
||||
lastRefRedef(def, bb0, i0, next) and
|
||||
Impl::lastRefRedef(def, bb0, i0, next) and
|
||||
adjacentDefReachesUncertainRead(def, bb, i, bb0, i0)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Definition uncertainWriteDefinitionInput(UncertainWriteDefinition def) {
|
||||
uncertainWriteDefinitionInput(def, result)
|
||||
Impl::uncertainWriteDefinitionInput(def, result)
|
||||
}
|
||||
}
|
||||
|
||||
import Cached
|
||||
|
||||
/**
|
||||
* An extended static single assignment (SSA) definition.
|
||||
*
|
||||
* This is either a normal SSA definition (`Definition`) or a
|
||||
* phi-read node (`PhiReadNode`).
|
||||
*
|
||||
* Only intended for internal use.
|
||||
*/
|
||||
class DefinitionExt extends Impl::DefinitionExt {
|
||||
override string toString() { result = this.(Ssa::Definition).toString() }
|
||||
|
||||
/** Gets the location of this definition. */
|
||||
Location getLocation() { result = this.(Ssa::Definition).getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A phi-read node.
|
||||
*
|
||||
* Only intended for internal use.
|
||||
*/
|
||||
class PhiReadNode extends DefinitionExt, Impl::PhiReadNode {
|
||||
override string toString() { result = "SSA phi read(" + this.getSourceVariable() + ")" }
|
||||
|
||||
override Location getLocation() { result = this.getBasicBlock().getLocation() }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user