mirror of
https://github.com/github/codeql.git
synced 2026-04-26 09:15:12 +02:00
Merge pull request #18869 from aschackmull/ssa/refactor3
Ssa: Update qltests including consistency checks
This commit is contained in:
@@ -3,22 +3,6 @@ import semmle.code.csharp.dataflow.internal.SsaImpl as Impl
|
||||
import Impl::Consistency
|
||||
import Ssa
|
||||
|
||||
class MyRelevantDefinition extends RelevantDefinition, Ssa::Definition {
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
class MyRelevantDefinitionExt extends RelevantDefinitionExt, Impl::DefinitionExt {
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
query predicate localDeclWithSsaDef(LocalVariableDeclExpr d) {
|
||||
// Local variables in C# must be initialized before every use, so uninitialized
|
||||
// local variables should not have an SSA definition, as that would imply that
|
||||
|
||||
@@ -456,9 +456,9 @@ module VariableCapture {
|
||||
Flow::clearsContent(asClosureNode(node), getCapturedVariableContent(c))
|
||||
}
|
||||
|
||||
class CapturedSsaDefinitionExt extends SsaImpl::DefinitionExt {
|
||||
CapturedSsaDefinitionExt() {
|
||||
this.getSourceVariable().getAssignable() = any(CapturedVariable v).asLocalScopeVariable()
|
||||
class CapturedSsaSourceVariable extends Ssa::SourceVariable {
|
||||
CapturedSsaSourceVariable() {
|
||||
this.getAssignable() = any(CapturedVariable v).asLocalScopeVariable()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -509,12 +509,12 @@ module SsaFlow {
|
||||
result.(Impl::ParameterNode).getParameter() = n.(ExplicitParameterNode).getSsaDefinition()
|
||||
}
|
||||
|
||||
predicate localFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo, boolean isUseStep) {
|
||||
Impl::localFlowStep(def, asNode(nodeFrom), asNode(nodeTo), isUseStep)
|
||||
predicate localFlowStep(Ssa::SourceVariable v, Node nodeFrom, Node nodeTo, boolean isUseStep) {
|
||||
Impl::localFlowStep(v, asNode(nodeFrom), asNode(nodeTo), isUseStep)
|
||||
}
|
||||
|
||||
predicate localMustFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
|
||||
Impl::localMustFlowStep(def, asNode(nodeFrom), asNode(nodeTo))
|
||||
predicate localMustFlowStep(Ssa::SourceVariable v, Node nodeFrom, Node nodeTo) {
|
||||
Impl::localMustFlowStep(v, asNode(nodeFrom), asNode(nodeTo))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -644,12 +644,10 @@ module LocalFlow {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the source variable of SSA definition `def` is an instance field.
|
||||
* Holds if the source variable `v` is an instance field.
|
||||
*/
|
||||
predicate usesInstanceField(SsaImpl::DefinitionExt def) {
|
||||
exists(Ssa::SourceVariables::FieldOrPropSourceVariable fp | fp = def.getSourceVariable() |
|
||||
not fp.getAssignable().(Modifiable).isStatic()
|
||||
)
|
||||
predicate isInstanceField(Ssa::SourceVariables::FieldOrPropSourceVariable v) {
|
||||
not v.getAssignable().(Modifiable).isStatic()
|
||||
}
|
||||
|
||||
predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) {
|
||||
@@ -749,10 +747,10 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
|
||||
(
|
||||
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
|
||||
or
|
||||
exists(SsaImpl::DefinitionExt def, boolean isUseStep |
|
||||
SsaFlow::localFlowStep(def, nodeFrom, nodeTo, isUseStep) and
|
||||
not LocalFlow::usesInstanceField(def) and
|
||||
not def instanceof VariableCapture::CapturedSsaDefinitionExt
|
||||
exists(Ssa::SourceVariable v, boolean isUseStep |
|
||||
SsaFlow::localFlowStep(v, nodeFrom, nodeTo, isUseStep) and
|
||||
not LocalFlow::isInstanceField(v) and
|
||||
not v instanceof VariableCapture::CapturedSsaSourceVariable
|
||||
|
|
||||
isUseStep = false
|
||||
or
|
||||
@@ -3007,13 +3005,13 @@ private predicate delegateCreationStep(Node nodeFrom, Node nodeTo) {
|
||||
|
||||
/** Extra data-flow steps needed for lambda flow analysis. */
|
||||
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) {
|
||||
exists(SsaImpl::DefinitionExt def |
|
||||
SsaFlow::localFlowStep(def, nodeFrom, nodeTo, _) and
|
||||
exists(Ssa::SourceVariable v |
|
||||
SsaFlow::localFlowStep(v, nodeFrom, nodeTo, _) and
|
||||
preservesValue = true
|
||||
|
|
||||
LocalFlow::usesInstanceField(def)
|
||||
LocalFlow::isInstanceField(v)
|
||||
or
|
||||
def instanceof VariableCapture::CapturedSsaDefinitionExt
|
||||
v instanceof VariableCapture::CapturedSsaSourceVariable
|
||||
)
|
||||
or
|
||||
delegateCreationStep(nodeFrom, nodeTo) and
|
||||
|
||||
@@ -60,12 +60,6 @@ class PhiNode = Impl::PhiNode;
|
||||
|
||||
module Consistency = Impl::Consistency;
|
||||
|
||||
module ExposedForTestingOnly {
|
||||
predicate ssaDefReachesReadExt = Impl::ssaDefReachesReadExt/4;
|
||||
|
||||
predicate phiHasInputFromBlockExt = Impl::phiHasInputFromBlockExt/3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` reads source variable `v`.
|
||||
*/
|
||||
@@ -967,13 +961,13 @@ private module Cached {
|
||||
import DataFlowIntegrationImpl
|
||||
|
||||
cached
|
||||
predicate localFlowStep(DefinitionExt def, Node nodeFrom, Node nodeTo, boolean isUseStep) {
|
||||
DataFlowIntegrationImpl::localFlowStep(def, nodeFrom, nodeTo, isUseStep)
|
||||
predicate localFlowStep(Ssa::SourceVariable v, Node nodeFrom, Node nodeTo, boolean isUseStep) {
|
||||
DataFlowIntegrationImpl::localFlowStep(v, nodeFrom, nodeTo, isUseStep)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate localMustFlowStep(DefinitionExt def, Node nodeFrom, Node nodeTo) {
|
||||
DataFlowIntegrationImpl::localMustFlowStep(def, nodeFrom, nodeTo)
|
||||
predicate localMustFlowStep(Ssa::SourceVariable v, Node nodeFrom, Node nodeTo) {
|
||||
DataFlowIntegrationImpl::localMustFlowStep(v, nodeFrom, nodeTo)
|
||||
}
|
||||
|
||||
signature predicate guardChecksSig(Guards::Guard g, Expr e, Guards::AbstractValue v);
|
||||
@@ -1000,9 +994,9 @@ private module Cached {
|
||||
|
||||
import Cached
|
||||
|
||||
private string getSplitString(DefinitionExt def) {
|
||||
private string getSplitString(Definition def) {
|
||||
exists(ControlFlow::BasicBlock bb, int i, ControlFlow::Node cfn |
|
||||
def.definesAt(_, bb, i, _) and
|
||||
def.definesAt(_, bb, i) and
|
||||
result = cfn.(ControlFlow::Nodes::ElementNode).getSplitsString()
|
||||
|
|
||||
cfn = bb.getNode(i)
|
||||
@@ -1012,48 +1006,13 @@ private string getSplitString(DefinitionExt def) {
|
||||
)
|
||||
}
|
||||
|
||||
string getToStringPrefix(DefinitionExt def) {
|
||||
string getToStringPrefix(Definition def) {
|
||||
result = "[" + getSplitString(def) + "] "
|
||||
or
|
||||
not exists(getSplitString(def)) and
|
||||
result = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* 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. */
|
||||
override Location getLocation() { result = this.(Ssa::Definition).getLocation() }
|
||||
|
||||
/** Gets the enclosing callable of this definition. */
|
||||
Callable getEnclosingCallable() { result = this.(Ssa::Definition).getEnclosingCallable() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A phi-read node.
|
||||
*
|
||||
* Only intended for internal use.
|
||||
*/
|
||||
class PhiReadNode extends DefinitionExt, Impl::PhiReadNode {
|
||||
override string toString() {
|
||||
result = getToStringPrefix(this) + "SSA phi read(" + this.getSourceVariable() + ")"
|
||||
}
|
||||
|
||||
override Location getLocation() { result = this.getBasicBlock().getLocation() }
|
||||
|
||||
override Callable getEnclosingCallable() {
|
||||
result = this.getSourceVariable().getEnclosingCallable()
|
||||
}
|
||||
}
|
||||
|
||||
private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInputSig {
|
||||
private import csharp as Cs
|
||||
private import semmle.code.csharp.controlflow.BasicBlocks
|
||||
|
||||
@@ -6,7 +6,7 @@ phiReadNode
|
||||
| Test.cs:25:16:25:16 | SSA phi read(x) | Test.cs:8:13:8:13 | x |
|
||||
| Test.cs:90:9:97:9 | SSA phi read(x) | Test.cs:78:13:78:13 | x |
|
||||
| Test.cs:99:9:99:15 | SSA phi read(x) | Test.cs:78:13:78:13 | x |
|
||||
phiReadNodeRead
|
||||
phiReadNodeFirstRead
|
||||
| DefUse.cs:80:30:80:31 | SSA phi read(this.Field2) | DefUse.cs:63:9:63:14 | this.Field2 | DefUse.cs:80:37:80:42 | access to field Field2 |
|
||||
| Fields.cs:63:16:63:28 | SSA phi read(this.LoopField) | Fields.cs:65:24:65:32 | this.LoopField | Fields.cs:65:24:65:32 | access to field LoopField |
|
||||
| Patterns.cs:20:9:38:9 | SSA phi read(o) | Patterns.cs:7:16:7:16 | o | Patterns.cs:20:17:20:17 | access to local variable o |
|
||||
@@ -15,16 +15,21 @@ phiReadNodeRead
|
||||
| Test.cs:90:9:97:9 | SSA phi read(x) | Test.cs:78:13:78:13 | x | Test.cs:92:17:92:17 | access to local variable x |
|
||||
| Test.cs:90:9:97:9 | SSA phi read(x) | Test.cs:78:13:78:13 | x | Test.cs:96:17:96:17 | access to local variable x |
|
||||
| Test.cs:99:9:99:15 | SSA phi read(x) | Test.cs:78:13:78:13 | x | Test.cs:99:13:99:13 | access to local variable x |
|
||||
| Test.cs:99:9:99:15 | SSA phi read(x) | Test.cs:78:13:78:13 | x | Test.cs:104:17:104:17 | access to local variable x |
|
||||
phiReadInput
|
||||
| DefUse.cs:80:30:80:31 | SSA phi read(this.Field2) | DefUse.cs:63:9:63:18 | SSA def(this.Field2) |
|
||||
| DefUse.cs:80:30:80:31 | SSA phi read(this.Field2) | DefUse.cs:80:30:80:31 | SSA phi read(this.Field2) |
|
||||
| DefUse.cs:80:30:80:31 | SSA phi read(this.Field2) | DefUse.cs:64:13:64:18 | SSA read(this.Field2) |
|
||||
| DefUse.cs:80:30:80:31 | SSA phi read(this.Field2) | DefUse.cs:80:37:80:42 | SSA read(this.Field2) |
|
||||
| Fields.cs:63:16:63:28 | SSA phi read(this.LoopField) | Fields.cs:61:17:61:17 | SSA entry def(this.LoopField) |
|
||||
| Fields.cs:63:16:63:28 | SSA phi read(this.LoopField) | Fields.cs:63:16:63:28 | SSA phi read(this.LoopField) |
|
||||
| Patterns.cs:20:9:38:9 | SSA phi read(o) | Patterns.cs:7:16:7:23 | SSA def(o) |
|
||||
| Fields.cs:63:16:63:28 | SSA phi read(this.LoopField) | Fields.cs:65:24:65:32 | SSA read(this.LoopField) |
|
||||
| Patterns.cs:20:9:38:9 | SSA phi read(o) | Patterns.cs:8:13:8:13 | SSA read(o) |
|
||||
| Patterns.cs:20:9:38:9 | SSA phi read(o) | Patterns.cs:12:18:12:18 | SSA read(o) |
|
||||
| Patterns.cs:20:9:38:9 | SSA phi read(o) | Patterns.cs:16:18:16:18 | SSA read(o) |
|
||||
| Properties.cs:63:16:63:16 | SSA phi read(this.LoopProp) | Properties.cs:61:17:61:17 | SSA entry def(this.LoopProp) |
|
||||
| Properties.cs:63:16:63:16 | SSA phi read(this.LoopProp) | Properties.cs:63:16:63:16 | SSA phi read(this.LoopProp) |
|
||||
| Properties.cs:63:16:63:16 | SSA phi read(this.LoopProp) | Properties.cs:65:24:65:31 | SSA read(this.LoopProp) |
|
||||
| Test.cs:25:16:25:16 | SSA phi read(x) | Test.cs:24:9:24:15 | SSA phi(x) |
|
||||
| Test.cs:25:16:25:16 | SSA phi read(x) | Test.cs:25:16:25:16 | SSA phi read(x) |
|
||||
| Test.cs:25:16:25:16 | SSA phi read(x) | Test.cs:25:16:25:16 | SSA read(x) |
|
||||
| Test.cs:90:9:97:9 | SSA phi read(x) | Test.cs:78:13:78:17 | SSA def(x) |
|
||||
| Test.cs:90:9:97:9 | SSA phi read(x) | Test.cs:82:17:82:17 | SSA read(x) |
|
||||
| Test.cs:90:9:97:9 | SSA phi read(x) | Test.cs:86:17:86:17 | SSA read(x) |
|
||||
| Test.cs:99:9:99:15 | SSA phi read(x) | Test.cs:90:9:97:9 | SSA phi read(x) |
|
||||
| Test.cs:99:9:99:15 | SSA phi read(x) | Test.cs:92:17:92:17 | SSA read(x) |
|
||||
| Test.cs:99:9:99:15 | SSA phi read(x) | Test.cs:96:17:96:17 | SSA read(x) |
|
||||
|
||||
@@ -1,17 +1,21 @@
|
||||
import csharp
|
||||
import semmle.code.csharp.dataflow.internal.SsaImpl
|
||||
import ExposedForTestingOnly
|
||||
import Impl::TestAdjacentRefs as RefTest
|
||||
|
||||
query predicate phiReadNode(PhiReadNode phi, Ssa::SourceVariable v) { phi.getSourceVariable() = v }
|
||||
query predicate phiReadNode(RefTest::Ref phi, Ssa::SourceVariable v) {
|
||||
phi.isPhiRead() and phi.getSourceVariable() = v
|
||||
}
|
||||
|
||||
query predicate phiReadNodeRead(PhiReadNode phi, Ssa::SourceVariable v, ControlFlow::Node read) {
|
||||
phi.getSourceVariable() = v and
|
||||
exists(ControlFlow::BasicBlock bb, int i |
|
||||
ssaDefReachesReadExt(v, phi, bb, i) and
|
||||
query predicate phiReadNodeFirstRead(RefTest::Ref phi, Ssa::SourceVariable v, ControlFlow::Node read) {
|
||||
exists(RefTest::Ref r, ControlFlow::BasicBlock bb, int i |
|
||||
phi.isPhiRead() and
|
||||
RefTest::adjacentRefRead(phi, r) and
|
||||
r.accessAt(bb, i, v) and
|
||||
read = bb.getNode(i)
|
||||
)
|
||||
}
|
||||
|
||||
query predicate phiReadInput(PhiReadNode phi, DefinitionExt inp) {
|
||||
phiHasInputFromBlockExt(phi, inp, _)
|
||||
query predicate phiReadInput(RefTest::Ref phi, RefTest::Ref inp) {
|
||||
phi.isPhiRead() and
|
||||
RefTest::adjacentRefPhi(inp, phi)
|
||||
}
|
||||
|
||||
@@ -36,14 +36,12 @@ module SsaFlow {
|
||||
TExplicitParameterNode(result.(Impl::ParameterNode).getParameter()) = n
|
||||
}
|
||||
|
||||
predicate localFlowStep(
|
||||
SsaImpl::Impl::DefinitionExt def, Node nodeFrom, Node nodeTo, boolean isUseStep
|
||||
) {
|
||||
Impl::localFlowStep(def, asNode(nodeFrom), asNode(nodeTo), isUseStep)
|
||||
predicate localFlowStep(SsaSourceVariable v, Node nodeFrom, Node nodeTo, boolean isUseStep) {
|
||||
Impl::localFlowStep(v, asNode(nodeFrom), asNode(nodeTo), isUseStep)
|
||||
}
|
||||
|
||||
predicate localMustFlowStep(SsaImpl::Impl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
|
||||
Impl::localMustFlowStep(def, asNode(nodeFrom), asNode(nodeTo))
|
||||
predicate localMustFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
Impl::localMustFlowStep(_, asNode(nodeFrom), asNode(nodeTo))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -168,7 +168,7 @@ predicate localMustFlowStep(Node node1, Node node2) {
|
||||
node2.(ImplicitInstanceAccess).getInstanceAccess().(OwnInstanceAccess).getEnclosingCallable()
|
||||
)
|
||||
or
|
||||
SsaFlow::localMustFlowStep(_, node1, node2)
|
||||
SsaFlow::localMustFlowStep(node1, node2)
|
||||
or
|
||||
node2.asExpr().(CastingExpr).getExpr() = node1.asExpr()
|
||||
or
|
||||
|
||||
@@ -544,15 +544,13 @@ private module Cached {
|
||||
import DataFlowIntegrationImpl
|
||||
|
||||
cached
|
||||
predicate localFlowStep(Impl::DefinitionExt def, Node nodeFrom, Node nodeTo, boolean isUseStep) {
|
||||
not def instanceof UntrackedDef and
|
||||
DataFlowIntegrationImpl::localFlowStep(def, nodeFrom, nodeTo, isUseStep)
|
||||
predicate localFlowStep(TrackedVar v, Node nodeFrom, Node nodeTo, boolean isUseStep) {
|
||||
DataFlowIntegrationImpl::localFlowStep(v, nodeFrom, nodeTo, isUseStep)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate localMustFlowStep(Impl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
|
||||
not def instanceof UntrackedDef and
|
||||
DataFlowIntegrationImpl::localMustFlowStep(def, nodeFrom, nodeTo)
|
||||
predicate localMustFlowStep(TrackedVar v, Node nodeFrom, Node nodeTo) {
|
||||
DataFlowIntegrationImpl::localMustFlowStep(v, nodeFrom, nodeTo)
|
||||
}
|
||||
|
||||
signature predicate guardChecksSig(Guards::Guard g, Expr e, boolean branch);
|
||||
|
||||
@@ -1,19 +1,3 @@
|
||||
import codeql.ruby.dataflow.SSA
|
||||
import codeql.ruby.dataflow.internal.SsaImpl
|
||||
import Consistency
|
||||
|
||||
class MyRelevantDefinition extends RelevantDefinition, Ssa::Definition {
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
class MyRelevantDefinitionExt extends RelevantDefinitionExt, DefinitionExt {
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,12 +111,14 @@ module SsaFlow {
|
||||
n = toParameterNode(result.(Impl::ParameterNode).getParameter())
|
||||
}
|
||||
|
||||
predicate localFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo, boolean isUseStep) {
|
||||
Impl::localFlowStep(def, asNode(nodeFrom), asNode(nodeTo), isUseStep)
|
||||
predicate localFlowStep(
|
||||
SsaImpl::SsaInput::SourceVariable v, Node nodeFrom, Node nodeTo, boolean isUseStep
|
||||
) {
|
||||
Impl::localFlowStep(v, asNode(nodeFrom), asNode(nodeTo), isUseStep)
|
||||
}
|
||||
|
||||
predicate localMustFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
|
||||
Impl::localMustFlowStep(def, asNode(nodeFrom), asNode(nodeTo))
|
||||
predicate localMustFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
Impl::localMustFlowStep(_, asNode(nodeFrom), asNode(nodeTo))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,7 +177,7 @@ module LocalFlow {
|
||||
}
|
||||
|
||||
predicate localMustFlowStep(Node node1, Node node2) {
|
||||
SsaFlow::localMustFlowStep(_, node1, node2)
|
||||
SsaFlow::localMustFlowStep(node1, node2)
|
||||
or
|
||||
node1.asExpr() = node2.asExpr().(CfgNodes::ExprNodes::AssignExprCfgNode).getRhs()
|
||||
or
|
||||
@@ -525,10 +527,10 @@ private module Cached {
|
||||
(
|
||||
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
|
||||
or
|
||||
exists(SsaImpl::DefinitionExt def, boolean isUseStep |
|
||||
SsaFlow::localFlowStep(def, nodeFrom, nodeTo, isUseStep) and
|
||||
exists(SsaImpl::SsaInput::SourceVariable v, boolean isUseStep |
|
||||
SsaFlow::localFlowStep(v, nodeFrom, nodeTo, isUseStep) and
|
||||
// captured variables are handled by the shared `VariableCapture` library
|
||||
not def instanceof VariableCapture::CapturedSsaDefinitionExt
|
||||
not v instanceof VariableCapture::CapturedVariable
|
||||
|
|
||||
isUseStep = false
|
||||
or
|
||||
|
||||
@@ -75,12 +75,6 @@ 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) {
|
||||
v.getDeclaringScope() = bb.getScope() and
|
||||
@@ -387,13 +381,15 @@ private module Cached {
|
||||
import DataFlowIntegrationImpl
|
||||
|
||||
cached
|
||||
predicate localFlowStep(DefinitionExt def, Node nodeFrom, Node nodeTo, boolean isUseStep) {
|
||||
DataFlowIntegrationImpl::localFlowStep(def, nodeFrom, nodeTo, isUseStep)
|
||||
predicate localFlowStep(
|
||||
SsaInput::SourceVariable v, Node nodeFrom, Node nodeTo, boolean isUseStep
|
||||
) {
|
||||
DataFlowIntegrationImpl::localFlowStep(v, nodeFrom, nodeTo, isUseStep)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate localMustFlowStep(DefinitionExt def, Node nodeFrom, Node nodeTo) {
|
||||
DataFlowIntegrationImpl::localMustFlowStep(def, nodeFrom, nodeTo)
|
||||
predicate localMustFlowStep(SsaInput::SourceVariable v, Node nodeFrom, Node nodeTo) {
|
||||
DataFlowIntegrationImpl::localMustFlowStep(v, nodeFrom, nodeTo)
|
||||
}
|
||||
|
||||
signature predicate guardChecksSig(Cfg::CfgNodes::AstCfgNode g, Cfg::CfgNode e, boolean branch);
|
||||
|
||||
@@ -597,7 +597,7 @@ phiReadNode
|
||||
| ssa.rb:92:3:96:5 | SSA phi read(x) | ssa.rb:91:3:91:3 | x |
|
||||
| ssa.rb:94:3:95:10 | SSA phi read(self) | ssa.rb:90:1:103:3 | self |
|
||||
| ssa.rb:94:3:95:10 | SSA phi read(x) | ssa.rb:91:3:91:3 | x |
|
||||
phiReadNodeRead
|
||||
phiReadNodeFirstRead
|
||||
| parameters.rb:26:3:26:11 | SSA phi read(name) | parameters.rb:25:15:25:18 | name | parameters.rb:26:8:26:11 | name |
|
||||
| ssa.rb:5:3:13:5 | SSA phi read(self) | ssa.rb:1:1:16:3 | self | ssa.rb:15:3:15:8 | self |
|
||||
| ssa.rb:19:9:19:9 | SSA phi read(self) | ssa.rb:18:1:23:3 | self | ssa.rb:20:5:20:10 | self |
|
||||
@@ -607,12 +607,16 @@ phiReadNodeRead
|
||||
| ssa.rb:92:3:96:5 | SSA phi read(x) | ssa.rb:91:3:91:3 | x | ssa.rb:101:10:101:10 | x |
|
||||
phiReadInput
|
||||
| parameters.rb:26:3:26:11 | SSA phi read(name) | parameters.rb:25:15:25:18 | name |
|
||||
| ssa.rb:5:3:13:5 | SSA phi read(self) | ssa.rb:1:1:16:3 | self (m) |
|
||||
| parameters.rb:26:3:26:11 | SSA phi read(name) | parameters.rb:25:40:25:43 | SSA read(name) |
|
||||
| ssa.rb:5:3:13:5 | SSA phi read(self) | ssa.rb:8:5:8:14 | SSA read(self) |
|
||||
| ssa.rb:5:3:13:5 | SSA phi read(self) | ssa.rb:12:5:12:14 | SSA read(self) |
|
||||
| ssa.rb:19:9:19:9 | SSA phi read(self) | ssa.rb:18:1:23:3 | self (m1) |
|
||||
| ssa.rb:19:9:19:9 | SSA phi read(self) | ssa.rb:19:9:19:9 | SSA phi read(self) |
|
||||
| ssa.rb:92:3:96:5 | SSA phi read(self) | ssa.rb:90:1:103:3 | self (m12) |
|
||||
| ssa.rb:19:9:19:9 | SSA phi read(self) | ssa.rb:20:5:20:10 | SSA read(self) |
|
||||
| ssa.rb:92:3:96:5 | SSA phi read(self) | ssa.rb:93:5:93:10 | SSA read(self) |
|
||||
| ssa.rb:92:3:96:5 | SSA phi read(self) | ssa.rb:94:3:95:10 | SSA phi read(self) |
|
||||
| ssa.rb:92:3:96:5 | SSA phi read(x) | ssa.rb:91:3:91:3 | x |
|
||||
| ssa.rb:92:3:96:5 | SSA phi read(x) | ssa.rb:93:10:93:10 | SSA read(x) |
|
||||
| ssa.rb:92:3:96:5 | SSA phi read(x) | ssa.rb:94:3:95:10 | SSA phi read(x) |
|
||||
| ssa.rb:94:3:95:10 | SSA phi read(self) | ssa.rb:90:1:103:3 | self (m12) |
|
||||
| ssa.rb:94:3:95:10 | SSA phi read(self) | ssa.rb:95:5:95:10 | SSA read(self) |
|
||||
| ssa.rb:94:3:95:10 | SSA phi read(x) | ssa.rb:91:3:91:3 | x |
|
||||
| ssa.rb:94:3:95:10 | SSA phi read(x) | ssa.rb:95:10:95:10 | SSA read(x) |
|
||||
|
||||
@@ -2,7 +2,7 @@ import codeql.ruby.AST
|
||||
import codeql.ruby.CFG
|
||||
import codeql.ruby.dataflow.SSA
|
||||
import codeql.ruby.dataflow.internal.SsaImpl
|
||||
import ExposedForTestingOnly
|
||||
import Impl::TestAdjacentRefs as RefTest
|
||||
|
||||
query predicate definition(Ssa::Definition def, Variable v) { def.getSourceVariable() = v }
|
||||
|
||||
@@ -23,16 +23,20 @@ query predicate phi(Ssa::PhiNode phi, Variable v, Ssa::Definition input) {
|
||||
phi.getSourceVariable() = v and input = phi.getAnInput()
|
||||
}
|
||||
|
||||
query predicate phiReadNode(PhiReadNode phi, Variable v) { phi.getSourceVariable() = v }
|
||||
query predicate phiReadNode(RefTest::Ref phi, Variable v) {
|
||||
phi.isPhiRead() and phi.getSourceVariable() = v
|
||||
}
|
||||
|
||||
query predicate phiReadNodeRead(PhiReadNode phi, Variable v, CfgNode read) {
|
||||
phi.getSourceVariable() = v and
|
||||
exists(BasicBlock bb, int i |
|
||||
ssaDefReachesReadExt(v, phi, bb, i) and
|
||||
query predicate phiReadNodeFirstRead(RefTest::Ref phi, Variable v, CfgNode read) {
|
||||
exists(RefTest::Ref r, BasicBlock bb, int i |
|
||||
phi.isPhiRead() and
|
||||
RefTest::adjacentRefRead(phi, r) and
|
||||
r.accessAt(bb, i, v) and
|
||||
read = bb.getNode(i)
|
||||
)
|
||||
}
|
||||
|
||||
query predicate phiReadInput(PhiReadNode phi, DefinitionExt inp) {
|
||||
phiHasInputFromBlockExt(phi, inp, _)
|
||||
query predicate phiReadInput(RefTest::Ref phi, RefTest::Ref inp) {
|
||||
phi.isPhiRead() and
|
||||
RefTest::adjacentRefPhi(inp, phi)
|
||||
}
|
||||
|
||||
@@ -1,19 +1,3 @@
|
||||
import codeql.rust.dataflow.Ssa
|
||||
import codeql.rust.dataflow.internal.SsaImpl
|
||||
import Consistency
|
||||
|
||||
class MyRelevantDefinition extends RelevantDefinition, Ssa::Definition {
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
class MyRelevantDefinitionExt extends RelevantDefinitionExt, DefinitionExt {
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -608,12 +608,14 @@ module SsaFlow {
|
||||
n = toParameterNode(result.(SsaFlow::ParameterNode).getParameter())
|
||||
}
|
||||
|
||||
predicate localFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo, boolean isUseStep) {
|
||||
SsaFlow::localFlowStep(def, asNode(nodeFrom), asNode(nodeTo), isUseStep)
|
||||
predicate localFlowStep(
|
||||
SsaImpl::SsaInput::SourceVariable v, Node nodeFrom, Node nodeTo, boolean isUseStep
|
||||
) {
|
||||
SsaFlow::localFlowStep(v, asNode(nodeFrom), asNode(nodeTo), isUseStep)
|
||||
}
|
||||
|
||||
predicate localMustFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
|
||||
SsaFlow::localMustFlowStep(def, asNode(nodeFrom), asNode(nodeTo))
|
||||
predicate localMustFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
SsaFlow::localMustFlowStep(_, asNode(nodeFrom), asNode(nodeTo))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1205,9 +1207,9 @@ module RustDataFlow implements InputSig<Location> {
|
||||
(
|
||||
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
|
||||
or
|
||||
exists(SsaImpl::DefinitionExt def, boolean isUseStep |
|
||||
SsaFlow::localFlowStep(def, nodeFrom, nodeTo, isUseStep) and
|
||||
not def instanceof VariableCapture::CapturedSsaDefinitionExt
|
||||
exists(SsaImpl::SsaInput::SourceVariable v, boolean isUseStep |
|
||||
SsaFlow::localFlowStep(v, nodeFrom, nodeTo, isUseStep) and
|
||||
not v instanceof VariableCapture::CapturedVariable
|
||||
|
|
||||
isUseStep = false
|
||||
or
|
||||
@@ -1514,7 +1516,7 @@ module RustDataFlow implements InputSig<Location> {
|
||||
* must also apply to `node1`.
|
||||
*/
|
||||
predicate localMustFlowStep(Node node1, Node node2) {
|
||||
SsaFlow::localMustFlowStep(_, node1, node2)
|
||||
SsaFlow::localMustFlowStep(node1, node2)
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalMustFlowStep(node1
|
||||
.(Node::FlowSummaryNode)
|
||||
@@ -1688,10 +1690,6 @@ module VariableCapture {
|
||||
predicate clearsContent(Node node, CapturedVariableContent c) {
|
||||
Flow::clearsContent(asClosureNode(node), c.getVariable())
|
||||
}
|
||||
|
||||
class CapturedSsaDefinitionExt extends SsaImpl::DefinitionExt {
|
||||
CapturedSsaDefinitionExt() { this.getSourceVariable() instanceof CapturedVariable }
|
||||
}
|
||||
}
|
||||
|
||||
import MakeImpl<Location, RustDataFlow>
|
||||
|
||||
@@ -100,12 +100,6 @@ class PhiDefinition = Impl::PhiNode;
|
||||
|
||||
module Consistency = Impl::Consistency;
|
||||
|
||||
module ExposedForTestingOnly {
|
||||
predicate ssaDefReachesReadExt = Impl::ssaDefReachesReadExt/4;
|
||||
|
||||
predicate phiHasInputFromBlockExt = Impl::phiHasInputFromBlockExt/3;
|
||||
}
|
||||
|
||||
/** Holds if `v` is read at index `i` in basic block `bb`. */
|
||||
private predicate variableReadActual(BasicBlock bb, int i, Variable v) {
|
||||
exists(VariableAccess read |
|
||||
@@ -303,13 +297,15 @@ private module Cached {
|
||||
import DataFlowIntegrationImpl
|
||||
|
||||
cached
|
||||
predicate localFlowStep(DefinitionExt def, Node nodeFrom, Node nodeTo, boolean isUseStep) {
|
||||
DataFlowIntegrationImpl::localFlowStep(def, nodeFrom, nodeTo, isUseStep)
|
||||
predicate localFlowStep(
|
||||
SsaInput::SourceVariable v, Node nodeFrom, Node nodeTo, boolean isUseStep
|
||||
) {
|
||||
DataFlowIntegrationImpl::localFlowStep(v, nodeFrom, nodeTo, isUseStep)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate localMustFlowStep(DefinitionExt def, Node nodeFrom, Node nodeTo) {
|
||||
DataFlowIntegrationImpl::localMustFlowStep(def, nodeFrom, nodeTo)
|
||||
predicate localMustFlowStep(SsaInput::SourceVariable v, Node nodeFrom, Node nodeTo) {
|
||||
DataFlowIntegrationImpl::localMustFlowStep(v, nodeFrom, nodeTo)
|
||||
}
|
||||
|
||||
signature predicate guardChecksSig(CfgNodes::AstCfgNode g, Cfg::CfgNode e, boolean branch);
|
||||
@@ -334,33 +330,6 @@ private module Cached {
|
||||
import Cached
|
||||
private import codeql.rust.dataflow.Ssa
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
CfgNode getARead() { result = getARead(this) }
|
||||
|
||||
override string toString() { result = this.(Ssa::Definition).toString() }
|
||||
|
||||
override 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 = Impl::PhiReadNode.super.getLocation() }
|
||||
}
|
||||
|
||||
private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInputSig {
|
||||
class Expr extends CfgNodes::AstCfgNode {
|
||||
predicate hasCfgNode(SsaInput::BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
|
||||
@@ -535,14 +535,15 @@ phi
|
||||
phiReadNode
|
||||
| main.rs:104:11:105:12 | SSA phi read(s1) | main.rs:102:9:102:10 | s1 |
|
||||
| main.rs:493:5:497:5 | SSA phi read(x) | main.rs:492:9:492:9 | x |
|
||||
phiReadNodeRead
|
||||
phiReadNodeFirstRead
|
||||
| main.rs:104:11:105:12 | SSA phi read(s1) | main.rs:102:9:102:10 | s1 | main.rs:105:11:105:12 | s1 |
|
||||
| main.rs:493:5:497:5 | SSA phi read(x) | main.rs:492:9:492:9 | x | main.rs:500:19:500:19 | x |
|
||||
| main.rs:493:5:497:5 | SSA phi read(x) | main.rs:492:9:492:9 | x | main.rs:502:19:502:19 | x |
|
||||
phiReadInput
|
||||
| main.rs:104:11:105:12 | SSA phi read(s1) | main.rs:102:9:102:10 | s1 |
|
||||
| main.rs:104:11:105:12 | SSA phi read(s1) | main.rs:104:11:105:12 | SSA phi read(s1) |
|
||||
| main.rs:493:5:497:5 | SSA phi read(x) | main.rs:492:9:492:9 | x |
|
||||
| main.rs:104:11:105:12 | SSA phi read(s1) | main.rs:105:11:105:12 | SSA read(s1) |
|
||||
| main.rs:493:5:497:5 | SSA phi read(x) | main.rs:494:19:494:19 | SSA read(x) |
|
||||
| main.rs:493:5:497:5 | SSA phi read(x) | main.rs:496:19:496:19 | SSA read(x) |
|
||||
ultimateDef
|
||||
| main.rs:191:9:191:44 | phi | main.rs:191:22:191:23 | a3 |
|
||||
| main.rs:191:9:191:44 | phi | main.rs:191:42:191:43 | a3 |
|
||||
|
||||
@@ -3,7 +3,7 @@ import codeql.rust.controlflow.BasicBlocks
|
||||
import codeql.rust.controlflow.ControlFlowGraph
|
||||
import codeql.rust.dataflow.Ssa
|
||||
import codeql.rust.dataflow.internal.SsaImpl
|
||||
import ExposedForTestingOnly
|
||||
import Impl::TestAdjacentRefs as RefTest
|
||||
|
||||
query predicate definition(Ssa::Definition def, Variable v) { def.getSourceVariable() = v }
|
||||
|
||||
@@ -24,18 +24,22 @@ query predicate phi(Ssa::PhiDefinition phi, Variable v, Ssa::Definition input) {
|
||||
phi.getSourceVariable() = v and input = phi.getAnInput()
|
||||
}
|
||||
|
||||
query predicate phiReadNode(PhiReadNode phi, Variable v) { phi.getSourceVariable() = v }
|
||||
query predicate phiReadNode(RefTest::Ref phi, Variable v) {
|
||||
phi.isPhiRead() and phi.getSourceVariable() = v
|
||||
}
|
||||
|
||||
query predicate phiReadNodeRead(PhiReadNode phi, Variable v, CfgNode read) {
|
||||
phi.getSourceVariable() = v and
|
||||
exists(BasicBlock bb, int i |
|
||||
ssaDefReachesReadExt(v, phi, bb, i) and
|
||||
query predicate phiReadNodeFirstRead(RefTest::Ref phi, Variable v, CfgNode read) {
|
||||
exists(RefTest::Ref r, BasicBlock bb, int i |
|
||||
phi.isPhiRead() and
|
||||
RefTest::adjacentRefRead(phi, r) and
|
||||
r.accessAt(bb, i, v) and
|
||||
read = bb.getNode(i)
|
||||
)
|
||||
}
|
||||
|
||||
query predicate phiReadInput(PhiReadNode phi, DefinitionExt inp) {
|
||||
phiHasInputFromBlockExt(phi, inp, _)
|
||||
query predicate phiReadInput(RefTest::Ref phi, RefTest::Ref inp) {
|
||||
phi.isPhiRead() and
|
||||
RefTest::adjacentRefPhi(inp, phi)
|
||||
}
|
||||
|
||||
query predicate ultimateDef(Ssa::Definition def, Definition ult) {
|
||||
|
||||
@@ -1256,11 +1256,7 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
string toString() { result = this.(Definition).toString() }
|
||||
|
||||
/** Gets the location of this SSA definition. */
|
||||
Location getLocation() {
|
||||
exists(BasicBlock bb, int i | this.definesAt(_, bb, i, _) |
|
||||
if i = -1 then result = bb.getLocation() else result = bb.getNode(i).getLocation()
|
||||
)
|
||||
}
|
||||
Location getLocation() { result = this.(Definition).getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1346,70 +1342,34 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
*/
|
||||
class PhiReadNode extends DefinitionExt, TPhiReadNode {
|
||||
override string toString() { result = "SSA phi read(" + this.getSourceVariable() + ")" }
|
||||
|
||||
override Location getLocation() { result = this.getBasicBlock().getLocation() }
|
||||
}
|
||||
|
||||
/** Provides a set of consistency queries. */
|
||||
module Consistency {
|
||||
/** A definition that is relevant for the consistency queries. */
|
||||
abstract class RelevantDefinition extends Definition {
|
||||
/** Override this predicate to ensure locations in consistency results. */
|
||||
abstract predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
);
|
||||
}
|
||||
|
||||
/** A definition that is relevant for the consistency queries. */
|
||||
abstract class RelevantDefinitionExt extends DefinitionExt {
|
||||
/** Override this predicate to ensure locations in consistency results. */
|
||||
abstract predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
);
|
||||
}
|
||||
|
||||
/** Holds if a read can be reached from multiple definitions. */
|
||||
query predicate nonUniqueDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
query predicate nonUniqueDef(Definition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
not exists(unique(Definition def0 | ssaDefReachesRead(v, def0, bb, i)))
|
||||
}
|
||||
|
||||
/** Holds if a read can be reached from multiple definitions. */
|
||||
query predicate nonUniqueDefExt(
|
||||
RelevantDefinitionExt def, SourceVariable v, BasicBlock bb, int i
|
||||
) {
|
||||
ssaDefReachesReadExt(v, def, bb, i) and
|
||||
not exists(unique(DefinitionExt def0 | ssaDefReachesReadExt(v, def0, bb, i)))
|
||||
}
|
||||
|
||||
/** Holds if a read cannot be reached from a definition. */
|
||||
query predicate readWithoutDef(SourceVariable v, BasicBlock bb, int i) {
|
||||
variableRead(bb, i, v, _) and
|
||||
not ssaDefReachesRead(v, _, bb, i)
|
||||
}
|
||||
|
||||
/** Holds if a read cannot be reached from a definition. */
|
||||
query predicate readWithoutDefExt(SourceVariable v, BasicBlock bb, int i) {
|
||||
variableRead(bb, i, v, _) and
|
||||
not ssaDefReachesReadExt(v, _, bb, i)
|
||||
}
|
||||
|
||||
/** Holds if a definition cannot reach a read. */
|
||||
query predicate deadDef(RelevantDefinition def, SourceVariable v) {
|
||||
query predicate deadDef(Definition def, SourceVariable v) {
|
||||
v = def.getSourceVariable() and
|
||||
not ssaDefReachesRead(_, def, _, _) and
|
||||
not phiHasInputFromBlock(_, def, _) and
|
||||
not uncertainWriteDefinitionInput(_, def)
|
||||
}
|
||||
|
||||
/** Holds if a definition cannot reach a read. */
|
||||
query predicate deadDefExt(RelevantDefinitionExt def, SourceVariable v) {
|
||||
v = def.getSourceVariable() and
|
||||
not ssaDefReachesReadExt(_, def, _, _) and
|
||||
not phiHasInputFromBlockExt(_, def, _) and
|
||||
not uncertainWriteDefinitionInput(_, def)
|
||||
}
|
||||
|
||||
/** Holds if a read is not dominated by a definition. */
|
||||
query predicate notDominatedByDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
query predicate notDominatedByDef(Definition def, SourceVariable v, BasicBlock bb, int i) {
|
||||
exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef) |
|
||||
ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
(bb != bbDef or i < iDef)
|
||||
@@ -1419,20 +1379,6 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if a read is not dominated by a definition. */
|
||||
query predicate notDominatedByDefExt(
|
||||
RelevantDefinitionExt def, SourceVariable v, BasicBlock bb, int i
|
||||
) {
|
||||
exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef, _) |
|
||||
ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
(bb != bbDef or i < iDef)
|
||||
or
|
||||
ssaDefReachesReadExt(v, def, bb, i) and
|
||||
not ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** Provides the input to `DataFlowIntegration`. */
|
||||
@@ -1644,7 +1590,7 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
/** A synthesized SSA data flow node. */
|
||||
abstract private class SsaNodeImpl extends NodeImpl {
|
||||
/** Gets the underlying SSA definition. */
|
||||
abstract DefinitionExt getDefinitionExt();
|
||||
abstract deprecated DefinitionExt getDefinitionExt();
|
||||
|
||||
/** Gets the SSA definition this node corresponds to, if any. */
|
||||
Definition asDefinition() { this = TSsaDefinitionNode(result) }
|
||||
@@ -1664,7 +1610,10 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
|
||||
SsaDefinitionExtNodeImpl() { this = TSsaDefinitionNode(def) }
|
||||
|
||||
override DefinitionExt getDefinitionExt() { result = def }
|
||||
/** Gets the corresponding `DefinitionExt`. */
|
||||
DefinitionExt getDefExt() { result = def }
|
||||
|
||||
deprecated override DefinitionExt getDefinitionExt() { result = def }
|
||||
|
||||
override BasicBlock getBasicBlock() { result = def.getBasicBlock() }
|
||||
|
||||
@@ -1692,7 +1641,7 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
/** A node that represents a synthetic read of a source variable. */
|
||||
final class SsaSynthReadNode extends SsaNode {
|
||||
SsaSynthReadNode() {
|
||||
this.(SsaDefinitionExtNodeImpl).getDefinitionExt() instanceof PhiReadNode or
|
||||
this.(SsaDefinitionExtNodeImpl).getDefExt() instanceof PhiReadNode or
|
||||
this instanceof SsaInputNodeImpl
|
||||
}
|
||||
}
|
||||
@@ -1744,7 +1693,9 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
input = input_
|
||||
}
|
||||
|
||||
override SsaInputDefinitionExt getDefinitionExt() { result = def_ }
|
||||
SsaInputDefinitionExt getPhi() { result = def_ }
|
||||
|
||||
deprecated override SsaInputDefinitionExt getDefinitionExt() { result = def_ }
|
||||
|
||||
override BasicBlock getBasicBlock() { result = input_ }
|
||||
|
||||
@@ -1761,17 +1712,17 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
* Holds if `nodeFrom` corresponds to the reference to `v` at index `i` in
|
||||
* `bb`. The boolean `isUseStep` indicates whether `nodeFrom` is an actual
|
||||
* read. If it is false then `nodeFrom` may be any of the following: an
|
||||
* uncertain write, a certain write, a phi, or a phi read. `def` is the SSA
|
||||
* definition that is read/defined at `nodeFrom`.
|
||||
* uncertain write, a certain write, a phi, or a phi read.
|
||||
*/
|
||||
private predicate flowOutOf(
|
||||
DefinitionExt def, Node nodeFrom, SourceVariable v, BasicBlock bb, int i, boolean isUseStep
|
||||
Node nodeFrom, SourceVariable v, BasicBlock bb, int i, boolean isUseStep
|
||||
) {
|
||||
nodeFrom.(SsaDefinitionExtNodeImpl).getDefinitionExt() = def and
|
||||
def.definesAt(v, bb, i, _) and
|
||||
isUseStep = false
|
||||
exists(DefinitionExt def |
|
||||
nodeFrom.(SsaDefinitionExtNodeImpl).getDefExt() = def and
|
||||
def.definesAt(v, bb, i, _) and
|
||||
isUseStep = false
|
||||
)
|
||||
or
|
||||
ssaDefReachesReadExt(v, def, bb, i) and
|
||||
[nodeFrom, nodeFrom.(ExprPostUpdateNode).getPreUpdateNode()].(ReadNode).readsAt(bb, i, v) and
|
||||
isUseStep = true
|
||||
}
|
||||
@@ -1782,66 +1733,73 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
* `isUseStep` is `true` when `nodeFrom` is a (post-update) read node and
|
||||
* `nodeTo` is a read node or phi (read) node.
|
||||
*/
|
||||
predicate localFlowStep(DefinitionExt def, Node nodeFrom, Node nodeTo, boolean isUseStep) {
|
||||
(
|
||||
predicate localFlowStep(SourceVariable v, Node nodeFrom, Node nodeTo, boolean isUseStep) {
|
||||
exists(Definition def |
|
||||
// Flow from assignment into SSA definition
|
||||
DfInput::ssaDefAssigns(def, nodeFrom.(ExprNode).getExpr())
|
||||
or
|
||||
// Flow from parameter into entry definition
|
||||
DfInput::ssaDefInitializesParam(def, nodeFrom.(ParameterNode).getParameter())
|
||||
) and
|
||||
nodeTo.(SsaDefinitionExtNodeImpl).getDefinitionExt() = def and
|
||||
isUseStep = false
|
||||
|
|
||||
nodeTo.(SsaDefinitionNode).getDefinition() = def and
|
||||
v = def.getSourceVariable() and
|
||||
isUseStep = false
|
||||
)
|
||||
or
|
||||
// Flow from definition/read to next read
|
||||
exists(SourceVariable v, BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
|
||||
flowOutOf(def, nodeFrom, v, bb1, i1, isUseStep) and
|
||||
exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
|
||||
flowOutOf(nodeFrom, v, bb1, i1, isUseStep) and
|
||||
AdjacentSsaRefs::adjacentRefRead(bb1, i1, bb2, i2, v) and
|
||||
nodeTo.(ReadNode).readsAt(bb2, i2, v)
|
||||
)
|
||||
or
|
||||
// Flow from definition/read to next uncertain write
|
||||
exists(SourceVariable v, BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
|
||||
flowOutOf(def, nodeFrom, v, bb1, i1, isUseStep) and
|
||||
exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 |
|
||||
flowOutOf(nodeFrom, v, bb1, i1, isUseStep) and
|
||||
AdjacentSsaRefs::adjacentRefRead(bb1, i1, bb2, i2, v) and
|
||||
exists(UncertainWriteDefinition def2 |
|
||||
DfInput::allowFlowIntoUncertainDef(def2) and
|
||||
nodeTo.(SsaDefinitionExtNodeImpl).getDefinitionExt() = def2 and
|
||||
nodeTo.(SsaDefinitionNode).getDefinition() = def2 and
|
||||
def2.definesAt(v, bb2, i2)
|
||||
)
|
||||
)
|
||||
or
|
||||
// Flow from definition/read to phi input
|
||||
exists(
|
||||
SourceVariable v, BasicBlock bb, int i, BasicBlock input, BasicBlock bbPhi,
|
||||
DefinitionExt phi
|
||||
|
|
||||
flowOutOf(def, nodeFrom, v, bb, i, isUseStep) and
|
||||
exists(BasicBlock bb, int i, BasicBlock input, BasicBlock bbPhi, DefinitionExt phi |
|
||||
flowOutOf(nodeFrom, v, bb, i, isUseStep) and
|
||||
AdjacentSsaRefs::adjacentRefPhi(bb, i, input, bbPhi, v) and
|
||||
nodeTo = TSsaInputNode(phi, input) and
|
||||
phi.definesAt(v, bbPhi, -1, _)
|
||||
)
|
||||
or
|
||||
// Flow from input node to def
|
||||
nodeTo.(SsaDefinitionExtNodeImpl).getDefinitionExt() = def and
|
||||
def = nodeFrom.(SsaInputNodeImpl).getDefinitionExt() and
|
||||
isUseStep = false
|
||||
exists(DefinitionExt def |
|
||||
nodeTo.(SsaDefinitionExtNodeImpl).getDefExt() = def and
|
||||
def = nodeFrom.(SsaInputNodeImpl).getPhi() and
|
||||
v = def.getSourceVariable() and
|
||||
isUseStep = false
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if the value of `nodeTo` is given by `nodeFrom`. */
|
||||
predicate localMustFlowStep(DefinitionExt def, Node nodeFrom, Node nodeTo) {
|
||||
(
|
||||
predicate localMustFlowStep(SourceVariable v, Node nodeFrom, Node nodeTo) {
|
||||
exists(Definition def |
|
||||
// Flow from assignment into SSA definition
|
||||
DfInput::ssaDefAssigns(def, nodeFrom.(ExprNode).getExpr())
|
||||
or
|
||||
// Flow from parameter into entry definition
|
||||
DfInput::ssaDefInitializesParam(def, nodeFrom.(ParameterNode).getParameter())
|
||||
) and
|
||||
nodeTo.(SsaDefinitionExtNodeImpl).getDefinitionExt() = def
|
||||
|
|
||||
nodeTo.(SsaDefinitionNode).getDefinition() = def and
|
||||
v = def.getSourceVariable()
|
||||
)
|
||||
or
|
||||
// Flow from SSA definition to read
|
||||
nodeFrom.(SsaDefinitionExtNodeImpl).getDefinitionExt() = def and
|
||||
nodeTo.(ExprNode).getExpr() = DfInput::getARead(def)
|
||||
exists(DefinitionExt def |
|
||||
nodeFrom.(SsaDefinitionExtNodeImpl).getDefExt() = def and
|
||||
nodeTo.(ExprNode).getExpr() = DfInput::getARead(def) and
|
||||
v = def.getSourceVariable()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1943,4 +1901,86 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides query predicates for testing adjacent SSA references and
|
||||
* insertion of phi reads.
|
||||
*/
|
||||
module TestAdjacentRefs {
|
||||
private newtype TRef =
|
||||
TRefRead(BasicBlock bb, int i, SourceVariable v) { variableRead(bb, i, v, true) } or
|
||||
TRefDef(Definition def) or
|
||||
TRefPhiRead(BasicBlock bb, SourceVariable v) { synthPhiRead(bb, v) }
|
||||
|
||||
/**
|
||||
* An SSA reference. This is either a certain read, a definition, or a
|
||||
* synthesized phi read.
|
||||
*/
|
||||
class Ref extends TRef {
|
||||
/** Gets the source variable referenced by this reference. */
|
||||
SourceVariable getSourceVariable() {
|
||||
this = TRefRead(_, _, result)
|
||||
or
|
||||
exists(Definition def | this = TRefDef(def) and def.getSourceVariable() = result)
|
||||
or
|
||||
this = TRefPhiRead(_, result)
|
||||
}
|
||||
|
||||
/** Holds if this reference is a synthesized phi read. */
|
||||
predicate isPhiRead() { this = TRefPhiRead(_, _) }
|
||||
|
||||
/** Gets a textual representation of this SSA reference. */
|
||||
string toString() {
|
||||
this = TRefRead(_, _, _) and result = "SSA read(" + this.getSourceVariable() + ")"
|
||||
or
|
||||
exists(Definition def | this = TRefDef(def) and result = def.toString())
|
||||
or
|
||||
this = TRefPhiRead(_, _) and result = "SSA phi read(" + this.getSourceVariable() + ")"
|
||||
}
|
||||
|
||||
/** Gets the location of this SSA reference. */
|
||||
Location getLocation() {
|
||||
exists(BasicBlock bb, int i |
|
||||
this = TRefRead(bb, i, _) and bb.getNode(i).getLocation() = result
|
||||
)
|
||||
or
|
||||
exists(Definition def | this = TRefDef(def) and def.getLocation() = result)
|
||||
or
|
||||
exists(BasicBlock bb | this = TRefPhiRead(bb, _) and bb.getLocation() = result)
|
||||
}
|
||||
|
||||
/** Holds if this reference of `v` occurs in `bb` at index `i`. */
|
||||
predicate accessAt(BasicBlock bb, int i, SourceVariable v) {
|
||||
this = TRefRead(bb, i, v)
|
||||
or
|
||||
exists(Definition def | this = TRefDef(def) and def.definesAt(v, bb, i))
|
||||
or
|
||||
this = TRefPhiRead(bb, v) and i = -1
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `r2` is a certain read or uncertain write, and `r1` is the
|
||||
* unique prior reference.
|
||||
*/
|
||||
query predicate adjacentRefRead(Ref r1, Ref r2) {
|
||||
exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2, SourceVariable v |
|
||||
r1.accessAt(bb1, i1, v) and
|
||||
r2.accessAt(bb2, i2, v) and
|
||||
AdjacentSsaRefs::adjacentRefRead(bb1, i1, bb2, i2, v)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `phi` is a phi definition or phi read and `input` is one its
|
||||
* inputs without any other reference in-between.
|
||||
*/
|
||||
query predicate adjacentRefPhi(Ref input, Ref phi) {
|
||||
exists(BasicBlock bb, int i, BasicBlock bbPhi, SourceVariable v |
|
||||
input.accessAt(bb, i, v) and
|
||||
phi.accessAt(bbPhi, -1, v) and
|
||||
AdjacentSsaRefs::adjacentRefPhi(bb, i, _, bbPhi, v)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user