mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge pull request #20253 from aschackmull/shared/basicblock-signature2
Shared: Add and use a signature for basic blocks
This commit is contained in:
@@ -1880,9 +1880,7 @@ module IteratorFlow {
|
||||
}
|
||||
}
|
||||
|
||||
private module SsaInput implements SsaImpl::InputSig<Location> {
|
||||
import Ssa::InputSigCommon
|
||||
|
||||
private module SsaInput implements SsaImpl::InputSig<Location, IRCfg::BasicBlock> {
|
||||
class SourceVariable = IteratorFlow::SourceVariable;
|
||||
|
||||
/** A call to function that dereferences an iterator. */
|
||||
@@ -1960,7 +1958,7 @@ module IteratorFlow {
|
||||
* Holds if `(bb, i)` contains a write to an iterator that may have been obtained
|
||||
* by calling `begin` (or related functions) on the variable `v`.
|
||||
*/
|
||||
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
predicate variableWrite(IRCfg::BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
certain = false and
|
||||
exists(GetsIteratorCall beginCall, Instruction writeToDeref, IRBlock bbQual, int iQual |
|
||||
isIteratorStoreInstruction(beginCall, writeToDeref) and
|
||||
@@ -1971,12 +1969,12 @@ module IteratorFlow {
|
||||
}
|
||||
|
||||
/** Holds if `(bb, i)` reads the container variable `v`. */
|
||||
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
predicate variableRead(IRCfg::BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
Ssa::variableRead(bb, i, v, certain)
|
||||
}
|
||||
}
|
||||
|
||||
private module IteratorSsa = SsaImpl::Make<Location, SsaInput>;
|
||||
private module IteratorSsa = SsaImpl::Make<Location, IRCfg, SsaInput>;
|
||||
|
||||
private module DataFlowIntegrationInput implements IteratorSsa::DataFlowIntegrationInputSig {
|
||||
private import codeql.util.Void
|
||||
@@ -1989,7 +1987,7 @@ module IteratorFlow {
|
||||
)
|
||||
}
|
||||
|
||||
predicate hasCfgNode(SsaInput::BasicBlock bb, int i) { bb.getInstruction(i) = this }
|
||||
predicate hasCfgNode(IRCfg::BasicBlock bb, int i) { bb.getInstruction(i) = this }
|
||||
}
|
||||
|
||||
predicate ssaDefHasSource(IteratorSsa::WriteDefinition def) { none() }
|
||||
@@ -1999,20 +1997,16 @@ module IteratorFlow {
|
||||
class GuardValue = Void;
|
||||
|
||||
class Guard extends Void {
|
||||
predicate hasValueBranchEdge(
|
||||
SsaInput::BasicBlock bb1, SsaInput::BasicBlock bb2, GuardValue val
|
||||
) {
|
||||
predicate hasValueBranchEdge(IRCfg::BasicBlock bb1, IRCfg::BasicBlock bb2, GuardValue val) {
|
||||
none()
|
||||
}
|
||||
|
||||
predicate valueControlsBranchEdge(
|
||||
SsaInput::BasicBlock bb1, SsaInput::BasicBlock bb2, GuardValue val
|
||||
) {
|
||||
predicate valueControlsBranchEdge(IRCfg::BasicBlock bb1, IRCfg::BasicBlock bb2, GuardValue val) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
predicate guardDirectlyControlsBlock(Guard guard, SsaInput::BasicBlock bb, GuardValue val) {
|
||||
predicate guardDirectlyControlsBlock(Guard guard, IRCfg::BasicBlock bb, GuardValue val) {
|
||||
none()
|
||||
}
|
||||
|
||||
|
||||
@@ -891,15 +891,14 @@ private predicate baseSourceVariableIsGlobal(
|
||||
)
|
||||
}
|
||||
|
||||
private module SsaInput implements Ssa::InputSig<Location> {
|
||||
import InputSigCommon
|
||||
private module SsaInput implements Ssa::InputSig<Location, IRCfg::BasicBlock> {
|
||||
import SourceVariables
|
||||
|
||||
/**
|
||||
* Holds if the `i`'th write in block `bb` writes to the variable `v`.
|
||||
* `certain` is `true` if the write is guaranteed to overwrite the entire variable.
|
||||
*/
|
||||
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
predicate variableWrite(IRCfg::BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
DataFlowImplCommon::forceCachingInSameStage() and
|
||||
(
|
||||
exists(DefImpl def | def.hasIndexInBlock(v, bb, i) |
|
||||
@@ -917,7 +916,7 @@ private module SsaInput implements Ssa::InputSig<Location> {
|
||||
* Holds if the `i`'th read in block `bb` reads to the variable `v`.
|
||||
* `certain` is `true` if the read is guaranteed. For C++, this is always the case.
|
||||
*/
|
||||
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
predicate variableRead(IRCfg::BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
exists(UseImpl use | use.hasIndexInBlock(bb, i, v) |
|
||||
if use.isCertain() then certain = true else certain = false
|
||||
)
|
||||
@@ -965,7 +964,7 @@ class GlobalDef extends Definition {
|
||||
GlobalLikeVariable getVariable() { result = impl.getVariable() }
|
||||
}
|
||||
|
||||
private module SsaImpl = Ssa::Make<Location, SsaInput>;
|
||||
private module SsaImpl = Ssa::Make<Location, IRCfg, SsaInput>;
|
||||
|
||||
private module DataFlowIntegrationInput implements SsaImpl::DataFlowIntegrationInputSig {
|
||||
private import codeql.util.Boolean
|
||||
@@ -978,7 +977,7 @@ private module DataFlowIntegrationInput implements SsaImpl::DataFlowIntegrationI
|
||||
)
|
||||
}
|
||||
|
||||
predicate hasCfgNode(SsaInput::BasicBlock bb, int i) { bb.getInstruction(i) = this }
|
||||
predicate hasCfgNode(IRCfg::BasicBlock bb, int i) { bb.getInstruction(i) = this }
|
||||
}
|
||||
|
||||
Expr getARead(SsaImpl::Definition def) {
|
||||
@@ -1006,9 +1005,7 @@ private module DataFlowIntegrationInput implements SsaImpl::DataFlowIntegrationI
|
||||
class Guard instanceof IRGuards::IRGuardCondition {
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
predicate hasValueBranchEdge(
|
||||
SsaInput::BasicBlock bb1, SsaInput::BasicBlock bb2, GuardValue branch
|
||||
) {
|
||||
predicate hasValueBranchEdge(IRCfg::BasicBlock bb1, IRCfg::BasicBlock bb2, GuardValue branch) {
|
||||
exists(EdgeKind kind |
|
||||
super.getBlock() = bb1 and
|
||||
kind = getConditionalEdge(branch) and
|
||||
@@ -1017,13 +1014,13 @@ private module DataFlowIntegrationInput implements SsaImpl::DataFlowIntegrationI
|
||||
}
|
||||
|
||||
predicate valueControlsBranchEdge(
|
||||
SsaInput::BasicBlock bb1, SsaInput::BasicBlock bb2, GuardValue branch
|
||||
IRCfg::BasicBlock bb1, IRCfg::BasicBlock bb2, GuardValue branch
|
||||
) {
|
||||
this.hasValueBranchEdge(bb1, bb2, branch)
|
||||
}
|
||||
}
|
||||
|
||||
predicate guardDirectlyControlsBlock(Guard guard, SsaInput::BasicBlock bb, GuardValue branch) {
|
||||
predicate guardDirectlyControlsBlock(Guard guard, IRCfg::BasicBlock bb, GuardValue branch) {
|
||||
guard.(IRGuards::IRGuardCondition).controls(bb, branch)
|
||||
}
|
||||
|
||||
|
||||
@@ -768,21 +768,3 @@ private module Cached {
|
||||
}
|
||||
|
||||
import Cached
|
||||
|
||||
/**
|
||||
* Inputs to the shared SSA library's parameterized module that is shared
|
||||
* between the SSA pruning stage, and the final SSA stage.
|
||||
*/
|
||||
module InputSigCommon {
|
||||
class BasicBlock extends IRBlock {
|
||||
ControlFlowNode getNode(int i) { result = this.getInstruction(i) }
|
||||
|
||||
int length() { result = this.getInstructionCount() }
|
||||
}
|
||||
|
||||
class ControlFlowNode = Instruction;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) }
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import Instruction
|
||||
private import internal.IRBlockImports as Imports
|
||||
import Imports::EdgeKind
|
||||
private import Cached
|
||||
private import codeql.controlflow.BasicBlock as BB
|
||||
|
||||
/**
|
||||
* Holds if `block` is a block in `func` and `sortOverride`, `sortKey1`, and `sortKey2` are the
|
||||
@@ -263,6 +264,49 @@ private predicate isEntryBlock(TIRBlock block) {
|
||||
block = MkIRBlock(any(EnterFunctionInstruction enter))
|
||||
}
|
||||
|
||||
module IRCfg implements BB::CfgSig<Language::Location> {
|
||||
class ControlFlowNode = Instruction;
|
||||
|
||||
class SuccessorType = EdgeKind;
|
||||
|
||||
final private class FinalIRBlock = IRBlock;
|
||||
|
||||
class BasicBlock extends FinalIRBlock {
|
||||
ControlFlowNode getNode(int i) { result = this.getInstruction(i) }
|
||||
|
||||
ControlFlowNode getLastNode() { result = super.getLastInstruction() }
|
||||
|
||||
int length() { result = this.getInstructionCount() }
|
||||
|
||||
BasicBlock getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
BasicBlock getASuccessor(SuccessorType t) { result = super.getSuccessor(t) }
|
||||
|
||||
predicate strictlyDominates(BasicBlock bb) { super.strictlyDominates(bb) }
|
||||
|
||||
predicate dominates(BasicBlock bb) { super.dominates(bb) }
|
||||
|
||||
BasicBlock getImmediateDominator() { result.immediatelyDominates(this) }
|
||||
|
||||
predicate inDominanceFrontier(BasicBlock df) { super.dominanceFrontier() = df }
|
||||
|
||||
predicate strictlyPostDominates(BasicBlock bb) { super.strictlyPostDominates(bb) }
|
||||
|
||||
predicate postDominates(BasicBlock bb) { super.postDominates(bb) }
|
||||
}
|
||||
|
||||
class EntryBasicBlock extends BasicBlock {
|
||||
EntryBasicBlock() { isEntryBlock(this) }
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) {
|
||||
bb1.getASuccessor() = bb2 and
|
||||
bb1 = bb2.getImmediateDominator() and
|
||||
forall(BasicBlock pred | pred = bb2.getAPredecessor() and pred != bb1 | bb2.dominates(pred))
|
||||
}
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
|
||||
@@ -7,6 +7,7 @@ import Instruction
|
||||
private import internal.IRBlockImports as Imports
|
||||
import Imports::EdgeKind
|
||||
private import Cached
|
||||
private import codeql.controlflow.BasicBlock as BB
|
||||
|
||||
/**
|
||||
* Holds if `block` is a block in `func` and `sortOverride`, `sortKey1`, and `sortKey2` are the
|
||||
@@ -263,6 +264,49 @@ private predicate isEntryBlock(TIRBlock block) {
|
||||
block = MkIRBlock(any(EnterFunctionInstruction enter))
|
||||
}
|
||||
|
||||
module IRCfg implements BB::CfgSig<Language::Location> {
|
||||
class ControlFlowNode = Instruction;
|
||||
|
||||
class SuccessorType = EdgeKind;
|
||||
|
||||
final private class FinalIRBlock = IRBlock;
|
||||
|
||||
class BasicBlock extends FinalIRBlock {
|
||||
ControlFlowNode getNode(int i) { result = this.getInstruction(i) }
|
||||
|
||||
ControlFlowNode getLastNode() { result = super.getLastInstruction() }
|
||||
|
||||
int length() { result = this.getInstructionCount() }
|
||||
|
||||
BasicBlock getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
BasicBlock getASuccessor(SuccessorType t) { result = super.getSuccessor(t) }
|
||||
|
||||
predicate strictlyDominates(BasicBlock bb) { super.strictlyDominates(bb) }
|
||||
|
||||
predicate dominates(BasicBlock bb) { super.dominates(bb) }
|
||||
|
||||
BasicBlock getImmediateDominator() { result.immediatelyDominates(this) }
|
||||
|
||||
predicate inDominanceFrontier(BasicBlock df) { super.dominanceFrontier() = df }
|
||||
|
||||
predicate strictlyPostDominates(BasicBlock bb) { super.strictlyPostDominates(bb) }
|
||||
|
||||
predicate postDominates(BasicBlock bb) { super.postDominates(bb) }
|
||||
}
|
||||
|
||||
class EntryBasicBlock extends BasicBlock {
|
||||
EntryBasicBlock() { isEntryBlock(this) }
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) {
|
||||
bb1.getASuccessor() = bb2 and
|
||||
bb1 = bb2.getImmediateDominator() and
|
||||
forall(BasicBlock pred | pred = bb2.getAPredecessor() and pred != bb1 | bb2.dominates(pred))
|
||||
}
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
|
||||
@@ -7,6 +7,7 @@ import Instruction
|
||||
private import internal.IRBlockImports as Imports
|
||||
import Imports::EdgeKind
|
||||
private import Cached
|
||||
private import codeql.controlflow.BasicBlock as BB
|
||||
|
||||
/**
|
||||
* Holds if `block` is a block in `func` and `sortOverride`, `sortKey1`, and `sortKey2` are the
|
||||
@@ -263,6 +264,49 @@ private predicate isEntryBlock(TIRBlock block) {
|
||||
block = MkIRBlock(any(EnterFunctionInstruction enter))
|
||||
}
|
||||
|
||||
module IRCfg implements BB::CfgSig<Language::Location> {
|
||||
class ControlFlowNode = Instruction;
|
||||
|
||||
class SuccessorType = EdgeKind;
|
||||
|
||||
final private class FinalIRBlock = IRBlock;
|
||||
|
||||
class BasicBlock extends FinalIRBlock {
|
||||
ControlFlowNode getNode(int i) { result = this.getInstruction(i) }
|
||||
|
||||
ControlFlowNode getLastNode() { result = super.getLastInstruction() }
|
||||
|
||||
int length() { result = this.getInstructionCount() }
|
||||
|
||||
BasicBlock getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
BasicBlock getASuccessor(SuccessorType t) { result = super.getSuccessor(t) }
|
||||
|
||||
predicate strictlyDominates(BasicBlock bb) { super.strictlyDominates(bb) }
|
||||
|
||||
predicate dominates(BasicBlock bb) { super.dominates(bb) }
|
||||
|
||||
BasicBlock getImmediateDominator() { result.immediatelyDominates(this) }
|
||||
|
||||
predicate inDominanceFrontier(BasicBlock df) { super.dominanceFrontier() = df }
|
||||
|
||||
predicate strictlyPostDominates(BasicBlock bb) { super.strictlyPostDominates(bb) }
|
||||
|
||||
predicate postDominates(BasicBlock bb) { super.postDominates(bb) }
|
||||
}
|
||||
|
||||
class EntryBasicBlock extends BasicBlock {
|
||||
EntryBasicBlock() { isEntryBlock(this) }
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) {
|
||||
bb1.getASuccessor() = bb2 and
|
||||
bb1 = bb2.getImmediateDominator() and
|
||||
forall(BasicBlock pred | pred = bb2.getAPredecessor() and pred != bb1 | bb2.dominates(pred))
|
||||
}
|
||||
}
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
cached
|
||||
|
||||
@@ -29,7 +29,7 @@ predicate bbSuccInconsistency(ControlFlowElement pred, ControlFlowElement succ)
|
||||
succBB.getFirstNode() = succ.getAControlFlowNode()
|
||||
) and
|
||||
not exists(PreBasicBlock predBB, PreBasicBlock succBB |
|
||||
predBB.getLastElement() = pred and
|
||||
predBB.getLastNode() = pred and
|
||||
succBB = predBB.getASuccessor() and
|
||||
succBB.getFirstElement() = succ
|
||||
)
|
||||
@@ -41,12 +41,12 @@ predicate bbIntraSuccInconsistency(ControlFlowElement pred, ControlFlowElement s
|
||||
succ.getAControlFlowNode() = bb.getNode(i + 1)
|
||||
) and
|
||||
not exists(PreBasicBlock bb |
|
||||
bb.getLastElement() = pred and
|
||||
bb.getLastNode() = pred and
|
||||
bb.getASuccessor().getFirstElement() = succ
|
||||
) and
|
||||
not exists(PreBasicBlock bb, int i |
|
||||
bb.getElement(i) = pred and
|
||||
bb.getElement(i + 1) = succ
|
||||
bb.getNode(i) = pred and
|
||||
bb.getNode(i + 1) = succ
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import csharp
|
||||
private import ControlFlow::SuccessorTypes
|
||||
private import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl as CfgImpl
|
||||
private import CfgImpl::BasicBlocks as BasicBlocksImpl
|
||||
private import codeql.controlflow.BasicBlock as BB
|
||||
|
||||
/**
|
||||
* A basic block, that is, a maximal straight-line sequence of control flow nodes
|
||||
@@ -13,7 +14,12 @@ private import CfgImpl::BasicBlocks as BasicBlocksImpl
|
||||
*/
|
||||
final class BasicBlock extends BasicBlocksImpl::BasicBlock {
|
||||
/** Gets an immediate successor of this basic block of a given type, if any. */
|
||||
BasicBlock getASuccessorByType(ControlFlow::SuccessorType t) { result = this.getASuccessor(t) }
|
||||
BasicBlock getASuccessor(ControlFlow::SuccessorType t) { result = super.getASuccessor(t) }
|
||||
|
||||
/** DEPRECATED: Use `getASuccessor` instead. */
|
||||
deprecated BasicBlock getASuccessorByType(ControlFlow::SuccessorType t) {
|
||||
result = this.getASuccessor(t)
|
||||
}
|
||||
|
||||
/** Gets an immediate predecessor of this basic block of a given type, if any. */
|
||||
BasicBlock getAPredecessorByType(ControlFlow::SuccessorType t) {
|
||||
@@ -58,6 +64,8 @@ final class BasicBlock extends BasicBlocksImpl::BasicBlock {
|
||||
result.getFirstNode() = this.getLastNode().getAFalseSuccessor()
|
||||
}
|
||||
|
||||
BasicBlock getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
/** Gets the control flow node at a specific (zero-indexed) position in this basic block. */
|
||||
ControlFlow::Node getNode(int pos) { result = super.getNode(pos) }
|
||||
|
||||
@@ -330,3 +338,21 @@ final class ConditionBlock extends BasicBlock, BasicBlocksImpl::ConditionBasicBl
|
||||
super.edgeDominates(controlled, s)
|
||||
}
|
||||
}
|
||||
|
||||
private class BasicBlockAlias = BasicBlock;
|
||||
|
||||
private class EntryBasicBlockAlias = EntryBasicBlock;
|
||||
|
||||
module Cfg implements BB::CfgSig<Location> {
|
||||
class ControlFlowNode = ControlFlow::Node;
|
||||
|
||||
class SuccessorType = ControlFlow::SuccessorType;
|
||||
|
||||
class BasicBlock = BasicBlockAlias;
|
||||
|
||||
class EntryBasicBlock = EntryBasicBlockAlias;
|
||||
|
||||
predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) {
|
||||
BasicBlocksImpl::dominatingEdge(bb1, bb2)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ class ControlFlowElement extends ExprOrStmtParent, @control_flow_element {
|
||||
// all other nodes can use regular CFG dominance
|
||||
this instanceof Impl::SplitAstNode and
|
||||
cb.getLastNode() = this.getAControlFlowNode() and
|
||||
succ = cb.getASuccessorByType(s)
|
||||
succ = cb.getASuccessor(s)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
|
||||
@@ -999,7 +999,7 @@ module Internal {
|
||||
pragma[nomagic]
|
||||
private predicate preControlsDirect(Guard g, PreBasicBlocks::PreBasicBlock bb, AbstractValue v) {
|
||||
exists(PreBasicBlocks::ConditionBlock cb, ConditionalSuccessor s | cb.controls(bb, s) |
|
||||
v.branch(cb.getLastElement(), s, g)
|
||||
v.branch(cb.getLastNode(), s, g)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1146,9 +1146,9 @@ module Internal {
|
||||
/** Gets the successor block that is reached when guard `g` has abstract value `v`. */
|
||||
private PreBasicBlocks::PreBasicBlock getConditionalSuccessor(Guard g, AbstractValue v) {
|
||||
exists(PreBasicBlocks::ConditionBlock pred, ConditionalSuccessor s |
|
||||
v.branch(pred.getLastElement(), s, g)
|
||||
v.branch(pred.getLastNode(), s, g)
|
||||
|
|
||||
result = pred.getASuccessorByType(s)
|
||||
result = pred.getASuccessor(s)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import csharp
|
||||
private import Completion
|
||||
private import ControlFlowGraphImpl
|
||||
private import semmle.code.csharp.controlflow.ControlFlowGraph::ControlFlow as Cfg
|
||||
private import codeql.controlflow.BasicBlock as BB
|
||||
|
||||
private predicate startsBB(ControlFlowElement cfe) {
|
||||
not succ(_, cfe, _) and
|
||||
@@ -55,24 +56,34 @@ private predicate bbIDominates(PreBasicBlock dom, PreBasicBlock bb) =
|
||||
class PreBasicBlock extends ControlFlowElement {
|
||||
PreBasicBlock() { startsBB(this) }
|
||||
|
||||
PreBasicBlock getASuccessorByType(Cfg::SuccessorType t) {
|
||||
succ(this.getLastElement(), result, any(Completion c | t = c.getAMatchingSuccessorType()))
|
||||
PreBasicBlock getASuccessor(Cfg::SuccessorType t) {
|
||||
succ(this.getLastNode(), result, any(Completion c | t = c.getAMatchingSuccessorType()))
|
||||
}
|
||||
|
||||
PreBasicBlock getASuccessor() { result = this.getASuccessorByType(_) }
|
||||
deprecated PreBasicBlock getASuccessorByType(Cfg::SuccessorType t) {
|
||||
result = this.getASuccessor(t)
|
||||
}
|
||||
|
||||
PreBasicBlock getASuccessor() { result = this.getASuccessor(_) }
|
||||
|
||||
PreBasicBlock getAPredecessor() { result.getASuccessor() = this }
|
||||
|
||||
ControlFlowElement getElement(int pos) { bbIndex(this, result, pos) }
|
||||
ControlFlowElement getNode(int pos) { bbIndex(this, result, pos) }
|
||||
|
||||
ControlFlowElement getAnElement() { result = this.getElement(_) }
|
||||
deprecated ControlFlowElement getElement(int pos) { result = this.getNode(pos) }
|
||||
|
||||
ControlFlowElement getAnElement() { result = this.getNode(_) }
|
||||
|
||||
ControlFlowElement getFirstElement() { result = this }
|
||||
|
||||
ControlFlowElement getLastElement() { result = this.getElement(this.length() - 1) }
|
||||
ControlFlowElement getLastNode() { result = this.getNode(this.length() - 1) }
|
||||
|
||||
deprecated ControlFlowElement getLastElement() { result = this.getLastNode() }
|
||||
|
||||
int length() { result = strictcount(this.getAnElement()) }
|
||||
|
||||
PreBasicBlock getImmediateDominator() { bbIDominates(result, this) }
|
||||
|
||||
predicate immediatelyDominates(PreBasicBlock bb) { bbIDominates(this, bb) }
|
||||
|
||||
pragma[inline]
|
||||
@@ -84,45 +95,83 @@ class PreBasicBlock extends ControlFlowElement {
|
||||
or
|
||||
this.strictlyDominates(bb)
|
||||
}
|
||||
|
||||
predicate inDominanceFrontier(PreBasicBlock df) {
|
||||
this = df.getAPredecessor() and not bbIDominates(this, df)
|
||||
or
|
||||
exists(PreBasicBlock prev | prev.inDominanceFrontier(df) |
|
||||
bbIDominates(this, prev) and
|
||||
not bbIDominates(this, df)
|
||||
)
|
||||
}
|
||||
|
||||
/** Unsupported. Do not use. */
|
||||
predicate strictlyPostDominates(PreBasicBlock bb) { none() }
|
||||
|
||||
/** Unsupported. Do not use. */
|
||||
predicate postDominates(PreBasicBlock bb) {
|
||||
this.strictlyPostDominates(bb) or
|
||||
this = bb
|
||||
}
|
||||
}
|
||||
|
||||
private Completion getConditionalCompletion(ConditionalCompletion cc) {
|
||||
result.getInnerCompletion() = cc
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate conditionBlockImmediatelyControls(
|
||||
ConditionBlock cond, PreBasicBlock succ, ConditionalCompletion cc
|
||||
) {
|
||||
exists(ControlFlowElement last, Completion c |
|
||||
last = cond.getLastNode() and
|
||||
c = getConditionalCompletion(cc) and
|
||||
succ(last, succ, c) and
|
||||
// In the pre-CFG, we need to account for case where one predecessor node has
|
||||
// two edges to the same successor node. Assertion expressions are examples of
|
||||
// such nodes.
|
||||
not exists(Completion other |
|
||||
succ(last, succ, other) and
|
||||
other != c
|
||||
) and
|
||||
forall(PreBasicBlock pred | pred = succ.getAPredecessor() and pred != cond |
|
||||
succ.dominates(pred)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
class ConditionBlock extends PreBasicBlock {
|
||||
ConditionBlock() {
|
||||
exists(Completion c | c = getConditionalCompletion(_) |
|
||||
succ(this.getLastElement(), _, c)
|
||||
succ(this.getLastNode(), _, c)
|
||||
or
|
||||
scopeLast(_, this.getLastElement(), c)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate immediatelyControls(PreBasicBlock succ, ConditionalCompletion cc) {
|
||||
exists(ControlFlowElement last, Completion c |
|
||||
last = this.getLastElement() and
|
||||
c = getConditionalCompletion(cc) and
|
||||
succ(last, succ, c) and
|
||||
// In the pre-CFG, we need to account for case where one predecessor node has
|
||||
// two edges to the same successor node. Assertion expressions are examples of
|
||||
// such nodes.
|
||||
not exists(Completion other |
|
||||
succ(last, succ, other) and
|
||||
other != c
|
||||
) and
|
||||
forall(PreBasicBlock pred | pred = succ.getAPredecessor() and pred != this |
|
||||
succ.dominates(pred)
|
||||
)
|
||||
scopeLast(_, this.getLastNode(), c)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate controls(PreBasicBlock controlled, Cfg::SuccessorTypes::ConditionalSuccessor s) {
|
||||
exists(PreBasicBlock succ, ConditionalCompletion c | this.immediatelyControls(succ, c) |
|
||||
exists(PreBasicBlock succ, ConditionalCompletion c |
|
||||
conditionBlockImmediatelyControls(this, succ, c)
|
||||
|
|
||||
succ.dominates(controlled) and
|
||||
s = c.getAMatchingSuccessorType()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module PreCfg implements BB::CfgSig<Location> {
|
||||
class ControlFlowNode = ControlFlowElement;
|
||||
|
||||
class SuccessorType = Cfg::SuccessorType;
|
||||
|
||||
class BasicBlock = PreBasicBlock;
|
||||
|
||||
class EntryBasicBlock extends BasicBlock {
|
||||
EntryBasicBlock() { entryBB(this) }
|
||||
}
|
||||
|
||||
predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) {
|
||||
conditionBlockImmediatelyControls(bb1, bb2, _)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,9 @@ module PreSsa {
|
||||
private import codeql.ssa.Ssa as SsaImplCommon
|
||||
|
||||
private predicate definitionAt(
|
||||
AssignableDefinition def, SsaInput::BasicBlock bb, int i, SsaInput::SourceVariable v
|
||||
AssignableDefinition def, PreBasicBlocks::PreBasicBlock bb, int i, SsaInput::SourceVariable v
|
||||
) {
|
||||
bb.getElement(i) = def.getExpr() and
|
||||
bb.getNode(i) = def.getExpr() and
|
||||
v = def.getTarget() and
|
||||
// In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x`
|
||||
not exists(TupleAssignmentDefinition first, TupleAssignmentDefinition second | first = def |
|
||||
@@ -30,7 +30,9 @@ module PreSsa {
|
||||
)
|
||||
}
|
||||
|
||||
predicate implicitEntryDef(Callable c, SsaInput::BasicBlock bb, SsaInput::SourceVariable v) {
|
||||
predicate implicitEntryDef(
|
||||
Callable c, PreBasicBlocks::PreBasicBlock bb, SsaInput::SourceVariable v
|
||||
) {
|
||||
c = v.getACallable() and
|
||||
scopeFirst(c, bb) and
|
||||
(
|
||||
@@ -79,19 +81,9 @@ module PreSsa {
|
||||
}
|
||||
}
|
||||
|
||||
module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||
class BasicBlock extends PreBasicBlocks::PreBasicBlock {
|
||||
ControlFlowNode getNode(int i) { result = this.getElement(i) }
|
||||
}
|
||||
|
||||
class ControlFlowNode = ControlFlowElement;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) }
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
private class ExitBasicBlock extends BasicBlock {
|
||||
ExitBasicBlock() { scopeLast(_, this.getLastElement(), _) }
|
||||
module SsaInput implements SsaImplCommon::InputSig<Location, PreBasicBlocks::PreBasicBlock> {
|
||||
private class ExitBasicBlock extends PreBasicBlocks::PreBasicBlock {
|
||||
ExitBasicBlock() { scopeLast(_, this.getLastNode(), _) }
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -129,7 +121,9 @@ module PreSsa {
|
||||
Callable getACallable() { result = c }
|
||||
}
|
||||
|
||||
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
predicate variableWrite(
|
||||
PreBasicBlocks::PreBasicBlock bb, int i, SourceVariable v, boolean certain
|
||||
) {
|
||||
exists(AssignableDefinition def |
|
||||
definitionAt(def, bb, i, v) and
|
||||
if def.getTargetAccess().isRefArgument() then certain = false else certain = true
|
||||
@@ -140,9 +134,11 @@ module PreSsa {
|
||||
certain = true
|
||||
}
|
||||
|
||||
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
predicate variableRead(
|
||||
PreBasicBlocks::PreBasicBlock bb, int i, SourceVariable v, boolean certain
|
||||
) {
|
||||
exists(AssignableRead read |
|
||||
read = bb.getElement(i) and
|
||||
read = bb.getNode(i) and
|
||||
read.getTarget() = v and
|
||||
certain = true
|
||||
)
|
||||
@@ -157,27 +153,27 @@ module PreSsa {
|
||||
}
|
||||
}
|
||||
|
||||
private module SsaImpl = SsaImplCommon::Make<Location, SsaInput>;
|
||||
private module SsaImpl = SsaImplCommon::Make<Location, PreBasicBlocks::PreCfg, SsaInput>;
|
||||
|
||||
class Definition extends SsaImpl::Definition {
|
||||
final AssignableRead getARead() {
|
||||
exists(SsaInput::BasicBlock bb, int i |
|
||||
exists(PreBasicBlocks::PreBasicBlock bb, int i |
|
||||
SsaImpl::ssaDefReachesRead(_, this, bb, i) and
|
||||
result = bb.getElement(i)
|
||||
result = bb.getNode(i)
|
||||
)
|
||||
}
|
||||
|
||||
final AssignableDefinition getDefinition() {
|
||||
exists(SsaInput::BasicBlock bb, int i, SsaInput::SourceVariable v |
|
||||
exists(PreBasicBlocks::PreBasicBlock bb, int i, SsaInput::SourceVariable v |
|
||||
this.definesAt(v, bb, i) and
|
||||
definitionAt(result, bb, i, v)
|
||||
)
|
||||
}
|
||||
|
||||
final AssignableRead getAFirstRead() {
|
||||
exists(SsaInput::BasicBlock bb, int i |
|
||||
exists(PreBasicBlocks::PreBasicBlock bb, int i |
|
||||
SsaImpl::firstUse(this, bb, i, true) and
|
||||
result = bb.getElement(i)
|
||||
result = bb.getNode(i)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -191,14 +187,14 @@ module PreSsa {
|
||||
not result instanceof PhiNode
|
||||
}
|
||||
|
||||
final predicate isLiveAtEndOfBlock(SsaInput::BasicBlock bb) {
|
||||
final predicate isLiveAtEndOfBlock(PreBasicBlocks::PreBasicBlock bb) {
|
||||
SsaImpl::ssaDefReachesEndOfBlock(bb, this, _)
|
||||
}
|
||||
|
||||
override Location getLocation() {
|
||||
result = this.getDefinition().getLocation()
|
||||
or
|
||||
exists(Callable c, SsaInput::BasicBlock bb, SsaInput::SourceVariable v |
|
||||
exists(Callable c, PreBasicBlocks::PreBasicBlock bb, SsaInput::SourceVariable v |
|
||||
this.definesAt(v, bb, -1) and
|
||||
implicitEntryDef(c, bb, v) and
|
||||
result = c.getLocation()
|
||||
@@ -213,10 +209,10 @@ module PreSsa {
|
||||
}
|
||||
|
||||
predicate adjacentReadPairSameVar(AssignableRead read1, AssignableRead read2) {
|
||||
exists(SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2 |
|
||||
read1 = bb1.getElement(i1) and
|
||||
exists(PreBasicBlocks::PreBasicBlock bb1, int i1, PreBasicBlocks::PreBasicBlock bb2, int i2 |
|
||||
read1 = bb1.getNode(i1) and
|
||||
SsaImpl::adjacentUseUse(bb1, i1, bb2, i2, _, true) and
|
||||
read2 = bb2.getElement(i2)
|
||||
read2 = bb2.getNode(i2)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -899,7 +899,7 @@ module BooleanSplitting {
|
||||
|
||||
/** Holds if control flow element `cfe` starts a split of this kind. */
|
||||
predicate startsSplit(AstNode cfe) {
|
||||
this.correlatesConditions(any(ConditionBlock cb | cb.getLastElement() = cfe), _, _)
|
||||
this.correlatesConditions(any(ConditionBlock cb | cb.getLastNode() = cfe), _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -941,7 +941,7 @@ module BooleanSplitting {
|
||||
/**
|
||||
* Holds if condition `cb` is a read of the SSA variable in this split.
|
||||
*/
|
||||
private predicate defCondition(ConditionBlock cb) { cb.getLastElement() = def.getARead() }
|
||||
private predicate defCondition(ConditionBlock cb) { cb.getLastNode() = def.getARead() }
|
||||
|
||||
/**
|
||||
* Holds if condition `cb` is a read of the SSA variable in this split,
|
||||
@@ -950,7 +950,7 @@ module BooleanSplitting {
|
||||
*/
|
||||
private predicate defConditionReachableFromRead(ConditionBlock cb, AssignableRead read) {
|
||||
this.defCondition(cb) and
|
||||
read = cb.getLastElement()
|
||||
read = cb.getLastNode()
|
||||
or
|
||||
exists(AssignableRead mid | this.defConditionReachableFromRead(cb, mid) |
|
||||
PreSsa::adjacentReadPairSameVar(read, mid) and
|
||||
@@ -970,9 +970,9 @@ module BooleanSplitting {
|
||||
override predicate correlatesConditions(ConditionBlock cb1, ConditionBlock cb2, boolean inverted) {
|
||||
this.firstDefCondition(cb1) and
|
||||
exists(AssignableRead read1, AssignableRead read2 |
|
||||
read1 = cb1.getLastElement() and
|
||||
read1 = cb1.getLastNode() and
|
||||
PreSsa::adjacentReadPairSameVar+(read1, read2) and
|
||||
read2 = cb2.getLastElement() and
|
||||
read2 = cb2.getLastNode() and
|
||||
inverted = false
|
||||
)
|
||||
}
|
||||
@@ -1088,7 +1088,7 @@ module BooleanSplitting {
|
||||
*/
|
||||
private predicate appliesToBlock(PreBasicBlock bb, Completion c) {
|
||||
this.appliesTo(bb) and
|
||||
exists(AstNode last | last = bb.getLastElement() |
|
||||
exists(AstNode last | last = bb.getLastNode() |
|
||||
(succ(last, _, c) or scopeLast(_, last, c)) and
|
||||
// Respect the value recorded in this split for all correlated conditions
|
||||
forall(boolean inverted | bb = this.getACorrelatedCondition(inverted) |
|
||||
@@ -1102,7 +1102,7 @@ module BooleanSplitting {
|
||||
|
||||
override predicate hasExit(AstNode pred, AstNode succ, Completion c) {
|
||||
exists(PreBasicBlock bb | this.appliesToBlock(bb, c) |
|
||||
pred = bb.getLastElement() and
|
||||
pred = bb.getLastNode() and
|
||||
succ(pred, succ, c) and
|
||||
// Exit this split if we can no longer reach a correlated condition
|
||||
not super.getSubKind().canReachCorrelatedCondition(succ)
|
||||
@@ -1111,7 +1111,7 @@ module BooleanSplitting {
|
||||
|
||||
override predicate hasExitScope(CfgScope scope, AstNode last, Completion c) {
|
||||
exists(PreBasicBlock bb | this.appliesToBlock(bb, c) |
|
||||
last = bb.getLastElement() and
|
||||
last = bb.getLastNode() and
|
||||
scopeLast(scope, last, c)
|
||||
)
|
||||
}
|
||||
@@ -1121,7 +1121,7 @@ module BooleanSplitting {
|
||||
pred = bb.getAnElement() and
|
||||
this.appliesSucc(pred, succ, c) and
|
||||
(
|
||||
pred = bb.getLastElement()
|
||||
pred = bb.getLastNode()
|
||||
implies
|
||||
(
|
||||
// We must still be able to reach a correlated condition to stay in this split
|
||||
|
||||
@@ -297,7 +297,7 @@ private predicate defNullImpliesStep(
|
||||
not exists(SuccessorTypes::ConditionalSuccessor s, NullValue nv |
|
||||
bb1.getLastNode() = getANullCheck(def1, s, nv).getAControlFlowNode()
|
||||
|
|
||||
bb2 = bb1.getASuccessorByType(s) and
|
||||
bb2 = bb1.getASuccessor(s) and
|
||||
nv.isNonNull()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import csharp
|
||||
*/
|
||||
module BaseSsa {
|
||||
private import AssignableDefinitions
|
||||
private import semmle.code.csharp.controlflow.BasicBlocks as BasicBlocks
|
||||
private import codeql.ssa.Ssa as SsaImplCommon
|
||||
|
||||
/**
|
||||
@@ -42,22 +43,12 @@ module BaseSsa {
|
||||
)
|
||||
}
|
||||
|
||||
private module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||
private module SsaInput implements SsaImplCommon::InputSig<Location, ControlFlow::BasicBlock> {
|
||||
private import semmle.code.csharp.controlflow.internal.PreSsa
|
||||
|
||||
class BasicBlock = ControlFlow::BasicBlock;
|
||||
|
||||
class ControlFlowNode = ControlFlow::Node;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) {
|
||||
result = bb.getImmediateDominator()
|
||||
}
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
class SourceVariable = PreSsa::SimpleLocalScopeVariable;
|
||||
|
||||
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
predicate variableWrite(ControlFlow::BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
exists(AssignableDefinition def |
|
||||
definitionAt(def, bb, i, v) and
|
||||
if def.isCertain() then certain = true else certain = false
|
||||
@@ -68,7 +59,7 @@ module BaseSsa {
|
||||
certain = true
|
||||
}
|
||||
|
||||
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
predicate variableRead(ControlFlow::BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
exists(AssignableRead read |
|
||||
read.getAControlFlowNode() = bb.getNode(i) and
|
||||
read.getTarget() = v and
|
||||
@@ -77,7 +68,7 @@ module BaseSsa {
|
||||
}
|
||||
}
|
||||
|
||||
private module SsaImpl = SsaImplCommon::Make<Location, SsaInput>;
|
||||
private module SsaImpl = SsaImplCommon::Make<Location, BasicBlocks::Cfg, SsaInput>;
|
||||
|
||||
class Definition extends SsaImpl::Definition {
|
||||
final AssignableRead getARead() {
|
||||
@@ -114,7 +105,7 @@ module BaseSsa {
|
||||
override Location getLocation() {
|
||||
result = this.getDefinition().getLocation()
|
||||
or
|
||||
exists(Callable c, SsaInput::BasicBlock bb, SsaInput::SourceVariable v |
|
||||
exists(Callable c, ControlFlow::BasicBlock bb, SsaInput::SourceVariable v |
|
||||
this.definesAt(v, bb, -1) and
|
||||
implicitEntryDef(c, bb, v) and
|
||||
result = c.getLocation()
|
||||
|
||||
@@ -264,6 +264,7 @@ predicate hasNodePath(ControlFlowReachabilityConfiguration conf, ExprNode n1, No
|
||||
/** Provides logic related to captured variables. */
|
||||
module VariableCapture {
|
||||
private import codeql.dataflow.VariableCapture as Shared
|
||||
private import semmle.code.csharp.controlflow.BasicBlocks as BasicBlocks
|
||||
|
||||
private predicate closureFlowStep(ControlFlow::Nodes::ExprNode e1, ControlFlow::Nodes::ExprNode e2) {
|
||||
e1 = LocalFlow::getALastEvalNode(e2)
|
||||
@@ -275,24 +276,15 @@ module VariableCapture {
|
||||
)
|
||||
}
|
||||
|
||||
private module CaptureInput implements Shared::InputSig<Location> {
|
||||
private module CaptureInput implements Shared::InputSig<Location, BasicBlocks::BasicBlock> {
|
||||
private import csharp as Cs
|
||||
private import semmle.code.csharp.controlflow.ControlFlowGraph as Cfg
|
||||
private import semmle.code.csharp.controlflow.BasicBlocks as BasicBlocks
|
||||
private import TaintTrackingPrivate as TaintTrackingPrivate
|
||||
|
||||
class BasicBlock extends BasicBlocks::BasicBlock {
|
||||
Callable getEnclosingCallable() { result = super.getCallable() }
|
||||
Callable basicBlockGetEnclosingCallable(BasicBlocks::BasicBlock bb) {
|
||||
result = bb.getCallable()
|
||||
}
|
||||
|
||||
class ControlFlowNode = Cfg::ControlFlow::Node;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) {
|
||||
result = bb.getImmediateDominator()
|
||||
}
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
private predicate thisAccess(ControlFlow::Node cfn, InstanceCallable c) {
|
||||
ThisFlow::thisAccessExpr(cfn.getAstNode()) and
|
||||
cfn.getEnclosingCallable().getEnclosingCallable*() = c
|
||||
@@ -359,7 +351,7 @@ module VariableCapture {
|
||||
}
|
||||
|
||||
class Expr extends ControlFlow::Node {
|
||||
predicate hasCfgNode(BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
predicate hasCfgNode(BasicBlocks::BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
}
|
||||
|
||||
class VariableWrite extends Expr {
|
||||
@@ -411,7 +403,7 @@ module VariableCapture {
|
||||
|
||||
class ClosureExpr = CaptureInput::ClosureExpr;
|
||||
|
||||
module Flow = Shared::Flow<Location, CaptureInput>;
|
||||
module Flow = Shared::Flow<Location, BasicBlocks::Cfg, CaptureInput>;
|
||||
|
||||
private Flow::ClosureNode asClosureNode(Node n) {
|
||||
result = n.(CaptureNode).getSynthesizedCaptureNode()
|
||||
|
||||
@@ -6,17 +6,10 @@ import csharp
|
||||
private import codeql.ssa.Ssa as SsaImplCommon
|
||||
private import AssignableDefinitions
|
||||
private import semmle.code.csharp.controlflow.internal.PreSsa
|
||||
private import semmle.code.csharp.controlflow.BasicBlocks as BasicBlocks
|
||||
private import semmle.code.csharp.controlflow.Guards as Guards
|
||||
|
||||
private module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||
class BasicBlock = ControlFlow::BasicBlock;
|
||||
|
||||
class ControlFlowNode = ControlFlow::Node;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() }
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
private module SsaInput implements SsaImplCommon::InputSig<Location, ControlFlow::BasicBlock> {
|
||||
class SourceVariable = Ssa::SourceVariable;
|
||||
|
||||
/**
|
||||
@@ -25,7 +18,7 @@ private module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||
*
|
||||
* This includes implicit writes via calls.
|
||||
*/
|
||||
predicate variableWrite(BasicBlock bb, int i, Ssa::SourceVariable v, boolean certain) {
|
||||
predicate variableWrite(ControlFlow::BasicBlock bb, int i, Ssa::SourceVariable v, boolean certain) {
|
||||
variableWriteDirect(bb, i, v, certain)
|
||||
or
|
||||
variableWriteQualifier(bb, i, v, certain)
|
||||
@@ -39,7 +32,7 @@ private module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||
*
|
||||
* This includes implicit reads via calls.
|
||||
*/
|
||||
predicate variableRead(BasicBlock bb, int i, Ssa::SourceVariable v, boolean certain) {
|
||||
predicate variableRead(ControlFlow::BasicBlock bb, int i, Ssa::SourceVariable v, boolean certain) {
|
||||
variableReadActual(bb, i, v) and
|
||||
certain = true
|
||||
or
|
||||
@@ -48,7 +41,7 @@ private module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||
}
|
||||
}
|
||||
|
||||
import SsaImplCommon::Make<Location, SsaInput> as Impl
|
||||
import SsaImplCommon::Make<Location, BasicBlocks::Cfg, SsaInput> as Impl
|
||||
|
||||
class Definition = Impl::Definition;
|
||||
|
||||
@@ -729,7 +722,7 @@ private predicate variableReadPseudo(ControlFlow::BasicBlock bb, int i, Ssa::Sou
|
||||
|
||||
pragma[noinline]
|
||||
deprecated private predicate adjacentDefRead(
|
||||
Definition def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2,
|
||||
Definition def, ControlFlow::BasicBlock bb1, int i1, ControlFlow::BasicBlock bb2, int i2,
|
||||
SsaInput::SourceVariable v
|
||||
) {
|
||||
Impl::adjacentDefRead(def, bb1, i1, bb2, i2) and
|
||||
@@ -737,8 +730,8 @@ deprecated private predicate adjacentDefRead(
|
||||
}
|
||||
|
||||
deprecated private predicate adjacentDefReachesRead(
|
||||
Definition def, SsaInput::SourceVariable v, SsaInput::BasicBlock bb1, int i1,
|
||||
SsaInput::BasicBlock bb2, int i2
|
||||
Definition def, SsaInput::SourceVariable v, ControlFlow::BasicBlock bb1, int i1,
|
||||
ControlFlow::BasicBlock bb2, int i2
|
||||
) {
|
||||
adjacentDefRead(def, bb1, i1, bb2, i2, v) and
|
||||
(
|
||||
@@ -747,7 +740,7 @@ deprecated private predicate adjacentDefReachesRead(
|
||||
SsaInput::variableRead(bb1, i1, v, true)
|
||||
)
|
||||
or
|
||||
exists(SsaInput::BasicBlock bb3, int i3 |
|
||||
exists(ControlFlow::BasicBlock bb3, int i3 |
|
||||
adjacentDefReachesRead(def, v, bb1, i1, bb3, i3) and
|
||||
SsaInput::variableRead(bb3, i3, _, false) and
|
||||
Impl::adjacentDefRead(def, bb3, i3, bb2, i2)
|
||||
@@ -755,7 +748,7 @@ deprecated private predicate adjacentDefReachesRead(
|
||||
}
|
||||
|
||||
deprecated private predicate adjacentDefReachesUncertainRead(
|
||||
Definition def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2
|
||||
Definition def, ControlFlow::BasicBlock bb1, int i1, ControlFlow::BasicBlock bb2, int i2
|
||||
) {
|
||||
exists(SsaInput::SourceVariable v |
|
||||
adjacentDefReachesRead(def, v, bb1, i1, bb2, i2) and
|
||||
@@ -766,12 +759,12 @@ deprecated private predicate adjacentDefReachesUncertainRead(
|
||||
/** Same as `lastRefRedef`, but skips uncertain reads. */
|
||||
pragma[nomagic]
|
||||
deprecated private predicate lastRefSkipUncertainReads(
|
||||
Definition def, SsaInput::BasicBlock bb, int i
|
||||
Definition def, ControlFlow::BasicBlock bb, int i
|
||||
) {
|
||||
Impl::lastRef(def, bb, i) and
|
||||
not SsaInput::variableRead(bb, i, def.getSourceVariable(), false)
|
||||
or
|
||||
exists(SsaInput::BasicBlock bb0, int i0 |
|
||||
exists(ControlFlow::BasicBlock bb0, int i0 |
|
||||
Impl::lastRef(def, bb0, i0) and
|
||||
adjacentDefReachesUncertainRead(def, bb, i, bb0, i0)
|
||||
)
|
||||
@@ -1054,7 +1047,7 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu
|
||||
predicate hasValueBranchEdge(BasicBlock bb1, BasicBlock bb2, GuardValue branch) {
|
||||
exists(ControlFlow::SuccessorTypes::ConditionalSuccessor s |
|
||||
this.getAControlFlowNode() = bb1.getLastNode() and
|
||||
bb2 = bb1.getASuccessorByType(s) and
|
||||
bb2 = bb1.getASuccessor(s) and
|
||||
s.getValue() = branch
|
||||
)
|
||||
}
|
||||
|
||||
@@ -98,6 +98,16 @@ class BasicBlock extends BbImpl::BasicBlock {
|
||||
/** Gets an immediate successor of this basic block of a given type, if any. */
|
||||
BasicBlock getASuccessor(Input::SuccessorType t) { result = super.getASuccessor(t) }
|
||||
|
||||
BasicBlock getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
BasicBlock getImmediateDominator() { result = super.getImmediateDominator() }
|
||||
|
||||
predicate inDominanceFrontier(BasicBlock df) { super.inDominanceFrontier(df) }
|
||||
|
||||
predicate strictlyPostDominates(BasicBlock bb) { super.strictlyPostDominates(bb) }
|
||||
|
||||
predicate postDominates(BasicBlock bb) { super.postDominates(bb) }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getASuccessor` instead.
|
||||
*
|
||||
@@ -145,3 +155,17 @@ class BasicBlock extends BbImpl::BasicBlock {
|
||||
class ExitBlock extends BasicBlock {
|
||||
ExitBlock() { this.getLastNode() instanceof ControlFlow::ExitNode }
|
||||
}
|
||||
|
||||
private class BasicBlockAlias = BasicBlock;
|
||||
|
||||
module Cfg implements BB::CfgSig<Location> {
|
||||
class ControlFlowNode = BbImpl::ControlFlowNode;
|
||||
|
||||
class SuccessorType = BbImpl::SuccessorType;
|
||||
|
||||
class BasicBlock = BasicBlockAlias;
|
||||
|
||||
class EntryBasicBlock extends BasicBlock instanceof BbImpl::EntryBasicBlock { }
|
||||
|
||||
predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) { BbImpl::dominatingEdge(bb1, bb2) }
|
||||
}
|
||||
|
||||
@@ -139,20 +139,17 @@ private predicate isNonFallThroughPredecessor(SwitchCase sc, ControlFlowNode pre
|
||||
)
|
||||
}
|
||||
|
||||
private module GuardsInput implements SharedGuards::InputSig<Location> {
|
||||
private module SuccessorTypes implements SharedGuards::SuccessorTypesSig<SuccessorType> {
|
||||
import SuccessorType
|
||||
}
|
||||
|
||||
private module GuardsInput implements SharedGuards::InputSig<Location, ControlFlowNode, BasicBlock> {
|
||||
private import java as J
|
||||
private import semmle.code.java.dataflow.internal.BaseSSA
|
||||
private import semmle.code.java.dataflow.NullGuards as NullGuards
|
||||
import SuccessorType
|
||||
|
||||
class ControlFlowNode = J::ControlFlowNode;
|
||||
|
||||
class NormalExitNode = ControlFlow::NormalExitNode;
|
||||
|
||||
class BasicBlock = J::BasicBlock;
|
||||
|
||||
predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) { J::dominatingEdge(bb1, bb2) }
|
||||
|
||||
class AstNode = ExprParent;
|
||||
|
||||
class Expr = J::Expr;
|
||||
@@ -382,7 +379,7 @@ private module GuardsInput implements SharedGuards::InputSig<Location> {
|
||||
}
|
||||
}
|
||||
|
||||
private module GuardsImpl = SharedGuards::Make<Location, GuardsInput>;
|
||||
private module GuardsImpl = SharedGuards::Make<Location, Cfg, SuccessorTypes, GuardsInput>;
|
||||
|
||||
private module LogicInputCommon {
|
||||
private import semmle.code.java.dataflow.NullGuards as NullGuards
|
||||
|
||||
@@ -157,17 +157,7 @@ private module BaseSsaImpl {
|
||||
|
||||
private import BaseSsaImpl
|
||||
|
||||
private module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||
private import java as J
|
||||
|
||||
class BasicBlock = J::BasicBlock;
|
||||
|
||||
class ControlFlowNode = J::ControlFlowNode;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) }
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
private module SsaInput implements SsaImplCommon::InputSig<Location, BasicBlock> {
|
||||
class SourceVariable = BaseSsaSourceVariable;
|
||||
|
||||
/**
|
||||
@@ -199,7 +189,7 @@ private module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||
}
|
||||
}
|
||||
|
||||
private module Impl = SsaImplCommon::Make<Location, SsaInput>;
|
||||
private module Impl = SsaImplCommon::Make<Location, Cfg, SsaInput>;
|
||||
|
||||
private import Cached
|
||||
|
||||
|
||||
@@ -69,28 +69,10 @@ private predicate closureFlowStep(Expr e1, Expr e2) {
|
||||
)
|
||||
}
|
||||
|
||||
private module CaptureInput implements VariableCapture::InputSig<Location> {
|
||||
private module CaptureInput implements VariableCapture::InputSig<Location, BasicBlock> {
|
||||
private import java as J
|
||||
|
||||
class BasicBlock instanceof J::BasicBlock {
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
ControlFlowNode getNode(int i) { result = super.getNode(i) }
|
||||
|
||||
int length() { result = super.length() }
|
||||
|
||||
Callable getEnclosingCallable() { result = super.getEnclosingCallable() }
|
||||
|
||||
Location getLocation() { result = super.getLocation() }
|
||||
}
|
||||
|
||||
class ControlFlowNode = J::ControlFlowNode;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) {
|
||||
result.(J::BasicBlock).immediatelyDominates(bb)
|
||||
}
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.(J::BasicBlock).getASuccessor() }
|
||||
Callable basicBlockGetEnclosingCallable(BasicBlock bb) { result = bb.getEnclosingCallable() }
|
||||
|
||||
//TODO: support capture of `this` in lambdas
|
||||
class CapturedVariable instanceof LocalScopeVariable {
|
||||
@@ -165,7 +147,7 @@ class CapturedVariable = CaptureInput::CapturedVariable;
|
||||
|
||||
class CapturedParameter = CaptureInput::CapturedParameter;
|
||||
|
||||
module CaptureFlow = VariableCapture::Flow<Location, CaptureInput>;
|
||||
module CaptureFlow = VariableCapture::Flow<Location, Cfg, CaptureInput>;
|
||||
|
||||
private CaptureFlow::ClosureNode asClosureNode(Node n) {
|
||||
result = n.(CaptureNode).getSynthesizedCaptureNode()
|
||||
|
||||
@@ -166,17 +166,7 @@ private predicate uncertainVariableUpdate(TrackedVar v, ControlFlowNode n, Basic
|
||||
uncertainVariableUpdate(v.getQualifier(), n, b, i)
|
||||
}
|
||||
|
||||
private module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||
private import java as J
|
||||
|
||||
class BasicBlock = J::BasicBlock;
|
||||
|
||||
class ControlFlowNode = J::ControlFlowNode;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) }
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
private module SsaInput implements SsaImplCommon::InputSig<Location, BasicBlock> {
|
||||
class SourceVariable = SsaSourceVariable;
|
||||
|
||||
/**
|
||||
@@ -218,7 +208,7 @@ private module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||
}
|
||||
}
|
||||
|
||||
import SsaImplCommon::Make<Location, SsaInput> as Impl
|
||||
import SsaImplCommon::Make<Location, Cfg, SsaInput> as Impl
|
||||
|
||||
final class Definition = Impl::Definition;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ private import semmle.javascript.dataflow.internal.VariableOrThis
|
||||
private import codeql.dataflow.VariableCapture
|
||||
private import semmle.javascript.dataflow.internal.sharedlib.DataFlowImplCommon as DataFlowImplCommon
|
||||
|
||||
module VariableCaptureConfig implements InputSig<js::Location> {
|
||||
module VariableCaptureConfig implements InputSig<js::Location, js::Cfg::BasicBlock> {
|
||||
private js::Function getLambdaFromVariable(js::LocalVariable variable) {
|
||||
result.getVariable() = variable
|
||||
or
|
||||
@@ -106,10 +106,8 @@ module VariableCaptureConfig implements InputSig<js::Location> {
|
||||
)
|
||||
}
|
||||
|
||||
class ControlFlowNode = js::ControlFlowNode;
|
||||
|
||||
class BasicBlock extends js::BasicBlock {
|
||||
Callable getEnclosingCallable() { result = this.getContainer().getFunctionBoundary() }
|
||||
Callable basicBlockGetEnclosingCallable(js::Cfg::BasicBlock bb) {
|
||||
result = bb.getContainer().getFunctionBoundary()
|
||||
}
|
||||
|
||||
class Callable extends js::StmtContainer {
|
||||
@@ -125,7 +123,7 @@ module VariableCaptureConfig implements InputSig<js::Location> {
|
||||
|
||||
class Expr extends js::AST::ValueNode {
|
||||
/** Holds if the `i`th node of basic block `bb` evaluates this expression. */
|
||||
predicate hasCfgNode(BasicBlock bb, int i) {
|
||||
predicate hasCfgNode(js::Cfg::BasicBlock bb, int i) {
|
||||
// Note: this is overridden for FunctionDeclStmt
|
||||
bb.getNode(i) = this
|
||||
}
|
||||
@@ -170,7 +168,7 @@ module VariableCaptureConfig implements InputSig<js::Location> {
|
||||
|
||||
js::Location getLocation() { none() } // Overridden in subclass
|
||||
|
||||
predicate hasCfgNode(BasicBlock bb, int i) { none() } // Overridden in subclass
|
||||
predicate hasCfgNode(js::Cfg::BasicBlock bb, int i) { none() } // Overridden in subclass
|
||||
|
||||
// note: langauge-specific
|
||||
js::DataFlow::Node getSource() { none() } // Overridden in subclass
|
||||
@@ -207,7 +205,7 @@ module VariableCaptureConfig implements InputSig<js::Location> {
|
||||
}
|
||||
|
||||
/** Holds if the `i`th node of basic block `bb` evaluates this expression. */
|
||||
override predicate hasCfgNode(BasicBlock bb, int i) {
|
||||
override predicate hasCfgNode(js::Cfg::BasicBlock bb, int i) {
|
||||
bb.getNode(i) = this.getCfgNodeOverride()
|
||||
or
|
||||
not exists(this.getCfgNodeOverride()) and
|
||||
@@ -226,7 +224,7 @@ module VariableCaptureConfig implements InputSig<js::Location> {
|
||||
|
||||
override CapturedVariable getVariable() { result = variable }
|
||||
|
||||
override predicate hasCfgNode(BasicBlock bb, int i) {
|
||||
override predicate hasCfgNode(js::Cfg::BasicBlock bb, int i) {
|
||||
// 'i' would normally be bound to 0, but we lower it to -1 so FunctionDeclStmts can be evaluated
|
||||
// at index 0.
|
||||
any(js::SsaImplicitInit def).definesAt(bb, _, variable.asLocalVariable()) and i = -1
|
||||
@@ -234,15 +232,9 @@ module VariableCaptureConfig implements InputSig<js::Location> {
|
||||
bb.(js::EntryBasicBlock).getContainer() = variable.asThisContainer() and i = -1
|
||||
}
|
||||
}
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() }
|
||||
|
||||
predicate entryBlock(BasicBlock bb) { bb instanceof js::EntryBasicBlock }
|
||||
}
|
||||
|
||||
module VariableCaptureOutput = Flow<js::Location, VariableCaptureConfig>;
|
||||
module VariableCaptureOutput = Flow<js::Location, js::Cfg, VariableCaptureConfig>;
|
||||
|
||||
js::DataFlow::Node getNodeFromClosureNode(VariableCaptureOutput::ClosureNode node) {
|
||||
result = TValueNode(node.(VariableCaptureOutput::ExprNode).getExpr())
|
||||
@@ -288,9 +280,9 @@ private module Debug {
|
||||
relevantContainer(node1.getContainer())
|
||||
}
|
||||
|
||||
predicate readBB(VariableRead read, BasicBlock bb, int i) { read.hasCfgNode(bb, i) }
|
||||
predicate readBB(VariableRead read, js::Cfg::BasicBlock bb, int i) { read.hasCfgNode(bb, i) }
|
||||
|
||||
predicate writeBB(VariableWrite write, BasicBlock bb, int i) { write.hasCfgNode(bb, i) }
|
||||
predicate writeBB(VariableWrite write, js::Cfg::BasicBlock bb, int i) { write.hasCfgNode(bb, i) }
|
||||
|
||||
int captureDegree(js::Function fun) {
|
||||
result = strictcount(CapturedVariable v | captures(fun, v))
|
||||
|
||||
@@ -9,11 +9,7 @@ private import codeql.ssa.Ssa
|
||||
private import semmle.javascript.internal.BasicBlockInternal as BasicBlockInternal
|
||||
private import semmle.javascript.dataflow.internal.VariableOrThis
|
||||
|
||||
module SsaConfig implements InputSig<js::Location> {
|
||||
class ControlFlowNode = js::ControlFlowNode;
|
||||
|
||||
class BasicBlock = js::BasicBlock;
|
||||
|
||||
module SsaConfig implements InputSig<js::Location, js::Cfg::BasicBlock> {
|
||||
class SourceVariable extends LocalVariableOrThis {
|
||||
SourceVariable() { not this.isCaptured() }
|
||||
}
|
||||
@@ -23,7 +19,7 @@ module SsaConfig implements InputSig<js::Location> {
|
||||
result.getContainer() = container
|
||||
}
|
||||
|
||||
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
predicate variableWrite(js::Cfg::BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
certain = true and
|
||||
(
|
||||
bb.defAt(i, v.asLocalVariable(), _)
|
||||
@@ -34,20 +30,15 @@ module SsaConfig implements InputSig<js::Location> {
|
||||
)
|
||||
}
|
||||
|
||||
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
predicate variableRead(js::Cfg::BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
bb.useAt(i, v.asLocalVariable(), _) and certain = true
|
||||
or
|
||||
certain = true and
|
||||
bb.getNode(i).(ThisUse).getBindingContainer() = v.asThisContainer()
|
||||
}
|
||||
|
||||
predicate getImmediateBasicBlockDominator = BasicBlockInternal::immediateDominator/1;
|
||||
|
||||
pragma[inline]
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
}
|
||||
|
||||
import Make<js::Location, SsaConfig>
|
||||
import Make<js::Location, js::Cfg, SsaConfig>
|
||||
|
||||
module SsaDataflowInput implements DataFlowIntegrationInputSig {
|
||||
private import codeql.util.Boolean
|
||||
@@ -55,7 +46,7 @@ module SsaDataflowInput implements DataFlowIntegrationInputSig {
|
||||
class Expr extends js::ControlFlowNode {
|
||||
Expr() { this = any(SsaConfig::SourceVariable v).getAUse() }
|
||||
|
||||
predicate hasCfgNode(js::BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
predicate hasCfgNode(js::Cfg::BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
}
|
||||
|
||||
predicate ssaDefHasSource(WriteDefinition def) {
|
||||
@@ -82,7 +73,7 @@ module SsaDataflowInput implements DataFlowIntegrationInputSig {
|
||||
* Holds if the evaluation of this guard to `branch` corresponds to the edge
|
||||
* from `bb1` to `bb2`.
|
||||
*/
|
||||
predicate hasValueBranchEdge(js::BasicBlock bb1, js::BasicBlock bb2, GuardValue branch) {
|
||||
predicate hasValueBranchEdge(js::Cfg::BasicBlock bb1, js::Cfg::BasicBlock bb2, GuardValue branch) {
|
||||
exists(js::ConditionGuardNode g |
|
||||
g.getTest() = this and
|
||||
bb1 = this.getBasicBlock() and
|
||||
@@ -96,13 +87,15 @@ module SsaDataflowInput implements DataFlowIntegrationInputSig {
|
||||
* branch edge from `bb1` to `bb2`. That is, following the edge from
|
||||
* `bb1` to `bb2` implies that this guard evaluated to `branch`.
|
||||
*/
|
||||
predicate valueControlsBranchEdge(js::BasicBlock bb1, js::BasicBlock bb2, GuardValue branch) {
|
||||
predicate valueControlsBranchEdge(
|
||||
js::Cfg::BasicBlock bb1, js::Cfg::BasicBlock bb2, GuardValue branch
|
||||
) {
|
||||
this.hasValueBranchEdge(bb1, bb2, branch)
|
||||
}
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
predicate guardDirectlyControlsBlock(Guard guard, js::BasicBlock bb, GuardValue branch) {
|
||||
predicate guardDirectlyControlsBlock(Guard guard, js::Cfg::BasicBlock bb, GuardValue branch) {
|
||||
exists(js::ConditionGuardNode g |
|
||||
g.getTest() = guard and
|
||||
g.dominates(bb) and
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import javascript
|
||||
private import semmle.javascript.internal.StmtContainers
|
||||
private import semmle.javascript.internal.CachedStages
|
||||
private import codeql.controlflow.BasicBlock as BB
|
||||
|
||||
/**
|
||||
* Holds if `nd` starts a new basic block.
|
||||
@@ -366,4 +367,50 @@ module Public {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
final private class FinalBasicBlock = BasicBlock;
|
||||
|
||||
module Cfg implements BB::CfgSig<Location> {
|
||||
private import javascript as Js
|
||||
private import codeql.util.Unit
|
||||
|
||||
class ControlFlowNode = Js::ControlFlowNode;
|
||||
|
||||
class SuccessorType = Unit;
|
||||
|
||||
class BasicBlock extends FinalBasicBlock {
|
||||
BasicBlock getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
BasicBlock getASuccessor(SuccessorType t) { result = super.getASuccessor() and exists(t) }
|
||||
|
||||
predicate strictlyDominates(BasicBlock bb) {
|
||||
this.(ReachableBasicBlock).strictlyDominates(bb)
|
||||
}
|
||||
|
||||
predicate dominates(BasicBlock bb) { this.(ReachableBasicBlock).dominates(bb) }
|
||||
|
||||
predicate inDominanceFrontier(BasicBlock df) {
|
||||
df.(ReachableJoinBlock).inDominanceFrontierOf(this)
|
||||
}
|
||||
|
||||
BasicBlock getImmediateDominator() { result = super.getImmediateDominator() }
|
||||
|
||||
predicate strictlyPostDominates(BasicBlock bb) {
|
||||
this.(ReachableBasicBlock).strictlyPostDominates(bb)
|
||||
}
|
||||
|
||||
predicate postDominates(BasicBlock bb) { this.(ReachableBasicBlock).postDominates(bb) }
|
||||
}
|
||||
|
||||
class EntryBasicBlock extends BasicBlock {
|
||||
EntryBasicBlock() { entryBB(this) }
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) {
|
||||
bb1.getASuccessor() = bb2 and
|
||||
bb1 = bb2.getImmediateDominator() and
|
||||
forall(BasicBlock pred | pred = bb2.getAPredecessor() and pred != bb1 | bb2.dominates(pred))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import python
|
||||
private import semmle.python.pointsto.PointsTo
|
||||
private import semmle.python.internal.CachedStages
|
||||
private import codeql.controlflow.BasicBlock as BB
|
||||
|
||||
/*
|
||||
* Note about matching parent and child nodes and CFG splitting:
|
||||
@@ -1082,9 +1083,15 @@ class BasicBlock extends @py_flow_node {
|
||||
* Dominance frontier of a node x is the set of all nodes `other` such that `this` dominates a predecessor
|
||||
* of `other` but does not strictly dominate `other`
|
||||
*/
|
||||
pragma[noinline]
|
||||
predicate dominanceFrontier(BasicBlock other) {
|
||||
this.dominates(other.getAPredecessor()) and not this.strictlyDominates(other)
|
||||
predicate dominanceFrontier(BasicBlock other) { this.inDominanceFrontier(other) }
|
||||
|
||||
predicate inDominanceFrontier(BasicBlock df) {
|
||||
this = df.getAPredecessor() and not this = df.getImmediateDominator()
|
||||
or
|
||||
exists(BasicBlock prev | prev.inDominanceFrontier(df) |
|
||||
this = prev.getImmediateDominator() and
|
||||
not this = df.getImmediateDominator()
|
||||
)
|
||||
}
|
||||
|
||||
private ControlFlowNode firstNode() { result = this }
|
||||
@@ -1246,3 +1253,56 @@ private predicate end_bb_likely_reachable(BasicBlock b) {
|
||||
not p = b.getLastNode()
|
||||
)
|
||||
}
|
||||
|
||||
private class ControlFlowNodeAlias = ControlFlowNode;
|
||||
|
||||
final private class FinalBasicBlock = BasicBlock;
|
||||
|
||||
module Cfg implements BB::CfgSig<Location> {
|
||||
class ControlFlowNode = ControlFlowNodeAlias;
|
||||
|
||||
class SuccessorType = Unit;
|
||||
|
||||
class BasicBlock extends FinalBasicBlock {
|
||||
// Note `PY:BasicBlock` does not have a `getLocation`.
|
||||
// (Instead it has a complicated location info logic.)
|
||||
// Using the location of the first node is simple
|
||||
// and we just need a way to identify the basic block
|
||||
// during debugging, so this will be serviceable.
|
||||
Location getLocation() { result = super.getNode(0).getLocation() }
|
||||
|
||||
int length() { result = count(int i | exists(this.getNode(i))) }
|
||||
|
||||
BasicBlock getASuccessor() { result = super.getASuccessor() }
|
||||
|
||||
BasicBlock getASuccessor(SuccessorType t) { result = super.getASuccessor() and exists(t) }
|
||||
|
||||
predicate strictlyDominates(BasicBlock bb) { super.strictlyDominates(bb) }
|
||||
|
||||
predicate dominates(BasicBlock bb) { super.dominates(bb) }
|
||||
|
||||
predicate inDominanceFrontier(BasicBlock df) { super.inDominanceFrontier(df) }
|
||||
|
||||
BasicBlock getImmediateDominator() { result = super.getImmediateDominator() }
|
||||
|
||||
/** Unsupported. Do not use. */
|
||||
predicate strictlyPostDominates(BasicBlock bb) { none() }
|
||||
|
||||
/** Unsupported. Do not use. */
|
||||
predicate postDominates(BasicBlock bb) {
|
||||
this.strictlyPostDominates(bb) or
|
||||
this = bb
|
||||
}
|
||||
}
|
||||
|
||||
class EntryBasicBlock extends BasicBlock {
|
||||
EntryBasicBlock() { this.getNode(0).isEntryNode() }
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) {
|
||||
bb1.getASuccessor() = bb2 and
|
||||
bb1 = bb2.getImmediateDominator() and
|
||||
forall(BasicBlock pred | pred = bb2.getAPredecessor() and pred != bb1 | bb2.dominates(pred))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ private import codeql.dataflow.VariableCapture as Shared
|
||||
// The first is the main implementation, the second is a performance motivated restriction.
|
||||
// The restriction is to clear any `CapturedVariableContent` before writing a new one
|
||||
// to avoid long access paths (see the link for a nice explanation).
|
||||
private module CaptureInput implements Shared::InputSig<Location> {
|
||||
private module CaptureInput implements Shared::InputSig<Location, Cfg::BasicBlock> {
|
||||
private import python as PY
|
||||
|
||||
additional class ExprCfgNode extends ControlFlowNode {
|
||||
@@ -23,24 +23,7 @@ private module CaptureInput implements Shared::InputSig<Location> {
|
||||
predicate isConstructor() { none() }
|
||||
}
|
||||
|
||||
class BasicBlock extends PY::BasicBlock {
|
||||
int length() { result = count(int i | exists(this.getNode(i))) }
|
||||
|
||||
Callable getEnclosingCallable() { result = this.getScope() }
|
||||
|
||||
// Note `PY:BasicBlock` does not have a `getLocation`.
|
||||
// (Instead it has a complicated location info logic.)
|
||||
// Using the location of the first node is simple
|
||||
// and we just need a way to identify the basic block
|
||||
// during debugging, so this will be serviceable.
|
||||
Location getLocation() { result = super.getNode(0).getLocation() }
|
||||
}
|
||||
|
||||
class ControlFlowNode = PY::ControlFlowNode;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() }
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
Callable basicBlockGetEnclosingCallable(Cfg::BasicBlock bb) { result = bb.getScope() }
|
||||
|
||||
class CapturedVariable extends LocalVariable {
|
||||
Function f;
|
||||
@@ -70,7 +53,7 @@ private module CaptureInput implements Shared::InputSig<Location> {
|
||||
}
|
||||
|
||||
class Expr extends ExprCfgNode {
|
||||
predicate hasCfgNode(BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
predicate hasCfgNode(Cfg::BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
}
|
||||
|
||||
class VariableWrite extends ControlFlowNode {
|
||||
@@ -80,7 +63,7 @@ private module CaptureInput implements Shared::InputSig<Location> {
|
||||
|
||||
CapturedVariable getVariable() { result = v }
|
||||
|
||||
predicate hasCfgNode(BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
predicate hasCfgNode(Cfg::BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
}
|
||||
|
||||
class VariableRead extends Expr {
|
||||
@@ -122,7 +105,7 @@ class CapturedVariable = CaptureInput::CapturedVariable;
|
||||
|
||||
class ClosureExpr = CaptureInput::ClosureExpr;
|
||||
|
||||
module Flow = Shared::Flow<Location, CaptureInput>;
|
||||
module Flow = Shared::Flow<Location, Cfg, CaptureInput>;
|
||||
|
||||
private Flow::ClosureNode asClosureNode(Node n) {
|
||||
result = n.(SynthCaptureNode).getSynthesizedCaptureNode()
|
||||
|
||||
@@ -10,6 +10,7 @@ private import internal.ControlFlowGraphImpl as CfgImpl
|
||||
private import CfgNodes
|
||||
private import SuccessorTypes
|
||||
private import CfgImpl::BasicBlocks as BasicBlocksImpl
|
||||
private import codeql.controlflow.BasicBlock as BB
|
||||
|
||||
/**
|
||||
* A basic block, that is, a maximal straight-line sequence of control flow nodes
|
||||
@@ -296,3 +297,23 @@ final class ConditionBlock extends BasicBlock, BasicBlocksImpl::ConditionBasicBl
|
||||
super.edgeDominates(controlled, s)
|
||||
}
|
||||
}
|
||||
|
||||
private class BasicBlockAlias = BasicBlock;
|
||||
|
||||
private class EntryBasicBlockAlias = EntryBasicBlock;
|
||||
|
||||
private class SuccessorTypeAlias = SuccessorType;
|
||||
|
||||
module Cfg implements BB::CfgSig<Location> {
|
||||
class ControlFlowNode = CfgNode;
|
||||
|
||||
class SuccessorType = SuccessorTypeAlias;
|
||||
|
||||
class BasicBlock = BasicBlockAlias;
|
||||
|
||||
class EntryBasicBlock = EntryBasicBlockAlias;
|
||||
|
||||
predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) {
|
||||
BasicBlocksImpl::dominatingEdge(bb1, bb2)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,6 +280,7 @@ predicate isNonConstantExpr(CfgNodes::ExprCfgNode n) {
|
||||
/** Provides logic related to captured variables. */
|
||||
module VariableCapture {
|
||||
private import codeql.dataflow.VariableCapture as Shared
|
||||
private import codeql.ruby.controlflow.BasicBlocks as BasicBlocks
|
||||
|
||||
private predicate closureFlowStep(CfgNodes::ExprCfgNode e1, CfgNodes::ExprCfgNode e2) {
|
||||
e1 = getALastEvalNode(e2)
|
||||
@@ -290,23 +291,14 @@ module VariableCapture {
|
||||
)
|
||||
}
|
||||
|
||||
private module CaptureInput implements Shared::InputSig<Location> {
|
||||
private module CaptureInput implements Shared::InputSig<Location, BasicBlocks::Cfg::BasicBlock> {
|
||||
private import codeql.ruby.controlflow.ControlFlowGraph as Cfg
|
||||
private import codeql.ruby.controlflow.BasicBlocks as BasicBlocks
|
||||
private import TaintTrackingPrivate as TaintTrackingPrivate
|
||||
|
||||
class BasicBlock extends BasicBlocks::BasicBlock {
|
||||
Callable getEnclosingCallable() { result = this.getScope() }
|
||||
Callable basicBlockGetEnclosingCallable(BasicBlocks::Cfg::BasicBlock bb) {
|
||||
result = bb.getScope()
|
||||
}
|
||||
|
||||
class ControlFlowNode = Cfg::CfgNode;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) {
|
||||
result = bb.getImmediateDominator()
|
||||
}
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
class CapturedVariable extends LocalVariable {
|
||||
CapturedVariable() {
|
||||
this.isCaptured() and
|
||||
@@ -377,7 +369,7 @@ module VariableCapture {
|
||||
|
||||
class ClosureExpr = CaptureInput::ClosureExpr;
|
||||
|
||||
module Flow = Shared::Flow<Location, CaptureInput>;
|
||||
module Flow = Shared::Flow<Location, BasicBlocks::Cfg, CaptureInput>;
|
||||
|
||||
private Flow::ClosureNode asClosureNode(Node n) {
|
||||
result = n.(CaptureNode).getSynthesizedCaptureNode()
|
||||
|
||||
@@ -4,22 +4,16 @@ module;
|
||||
private import codeql.ssa.Ssa as SsaImplCommon
|
||||
private import codeql.ruby.AST
|
||||
private import codeql.ruby.CFG as Cfg
|
||||
private import codeql.ruby.controlflow.BasicBlocks as BasicBlocks
|
||||
private import codeql.ruby.controlflow.internal.ControlFlowGraphImpl as ControlFlowGraphImpl
|
||||
private import codeql.ruby.dataflow.SSA
|
||||
private import codeql.ruby.ast.Variable
|
||||
private import Cfg::CfgNodes::ExprNodes
|
||||
|
||||
module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||
private class BasicBlock = BasicBlocks::Cfg::BasicBlock;
|
||||
|
||||
module SsaInput implements SsaImplCommon::InputSig<Location, BasicBlock> {
|
||||
private import codeql.ruby.controlflow.ControlFlowGraph as Cfg
|
||||
private import codeql.ruby.controlflow.BasicBlocks as BasicBlocks
|
||||
|
||||
class BasicBlock = BasicBlocks::BasicBlock;
|
||||
|
||||
class ControlFlowNode = Cfg::CfgNode;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() }
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
class SourceVariable = LocalVariable;
|
||||
|
||||
@@ -66,7 +60,7 @@ module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||
}
|
||||
}
|
||||
|
||||
import SsaImplCommon::Make<Location, SsaInput> as Impl
|
||||
import SsaImplCommon::Make<Location, BasicBlocks::Cfg, SsaInput> as Impl
|
||||
|
||||
class Definition = Impl::Definition;
|
||||
|
||||
@@ -220,15 +214,14 @@ private predicate hasVariableReadWithCapturedWrite(
|
||||
|
||||
pragma[noinline]
|
||||
deprecated private predicate adjacentDefReadExt(
|
||||
Definition def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2,
|
||||
SsaInput::SourceVariable v
|
||||
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SsaInput::SourceVariable v
|
||||
) {
|
||||
Impl::adjacentDefReadExt(def, _, bb1, i1, bb2, i2) and
|
||||
v = def.getSourceVariable()
|
||||
}
|
||||
|
||||
deprecated private predicate adjacentDefReachesReadExt(
|
||||
Definition def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2
|
||||
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
|
||||
) {
|
||||
exists(SsaInput::SourceVariable v | adjacentDefReadExt(def, bb1, i1, bb2, i2, v) |
|
||||
def.definesAt(v, bb1, i1)
|
||||
@@ -236,7 +229,7 @@ deprecated private predicate adjacentDefReachesReadExt(
|
||||
SsaInput::variableRead(bb1, i1, v, true)
|
||||
)
|
||||
or
|
||||
exists(SsaInput::BasicBlock bb3, int i3 |
|
||||
exists(BasicBlock bb3, int i3 |
|
||||
adjacentDefReachesReadExt(def, bb1, i1, bb3, i3) and
|
||||
SsaInput::variableRead(bb3, i3, _, false) and
|
||||
Impl::adjacentDefReadExt(def, _, bb3, i3, bb2, i2)
|
||||
@@ -244,7 +237,7 @@ deprecated private predicate adjacentDefReachesReadExt(
|
||||
}
|
||||
|
||||
deprecated private predicate adjacentDefReachesUncertainReadExt(
|
||||
Definition def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2
|
||||
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
|
||||
) {
|
||||
adjacentDefReachesReadExt(def, bb1, i1, bb2, i2) and
|
||||
SsaInput::variableRead(bb2, i2, _, false)
|
||||
@@ -252,13 +245,11 @@ deprecated private predicate adjacentDefReachesUncertainReadExt(
|
||||
|
||||
/** Same as `lastRefRedef`, but skips uncertain reads. */
|
||||
pragma[nomagic]
|
||||
deprecated private predicate lastRefSkipUncertainReadsExt(
|
||||
Definition def, SsaInput::BasicBlock bb, int i
|
||||
) {
|
||||
deprecated private predicate lastRefSkipUncertainReadsExt(Definition def, BasicBlock bb, int i) {
|
||||
Impl::lastRef(def, bb, i) and
|
||||
not SsaInput::variableRead(bb, i, def.getSourceVariable(), false)
|
||||
or
|
||||
exists(SsaInput::BasicBlock bb0, int i0 |
|
||||
exists(BasicBlock bb0, int i0 |
|
||||
Impl::lastRef(def, bb0, i0) and
|
||||
adjacentDefReachesUncertainReadExt(def, bb, i, bb0, i0)
|
||||
)
|
||||
@@ -479,7 +470,7 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu
|
||||
private import codeql.util.Boolean
|
||||
|
||||
class Expr extends Cfg::CfgNodes::ExprCfgNode {
|
||||
predicate hasCfgNode(SsaInput::BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
predicate hasCfgNode(BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
}
|
||||
|
||||
Expr getARead(Definition def) { result = Cached::getARead(def) }
|
||||
@@ -495,9 +486,7 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu
|
||||
* Holds if the evaluation of this guard to `branch` corresponds to the edge
|
||||
* from `bb1` to `bb2`.
|
||||
*/
|
||||
predicate hasValueBranchEdge(
|
||||
SsaInput::BasicBlock bb1, SsaInput::BasicBlock bb2, GuardValue branch
|
||||
) {
|
||||
predicate hasValueBranchEdge(BasicBlock bb1, BasicBlock bb2, GuardValue branch) {
|
||||
exists(Cfg::SuccessorTypes::ConditionalSuccessor s |
|
||||
this.getBasicBlock() = bb1 and
|
||||
bb2 = bb1.getASuccessor(s) and
|
||||
@@ -510,15 +499,13 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu
|
||||
* branch edge from `bb1` to `bb2`. That is, following the edge from
|
||||
* `bb1` to `bb2` implies that this guard evaluated to `branch`.
|
||||
*/
|
||||
predicate valueControlsBranchEdge(
|
||||
SsaInput::BasicBlock bb1, SsaInput::BasicBlock bb2, GuardValue branch
|
||||
) {
|
||||
predicate valueControlsBranchEdge(BasicBlock bb1, BasicBlock bb2, GuardValue branch) {
|
||||
this.hasValueBranchEdge(bb1, bb2, branch)
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if the guard `guard` controls block `bb` upon evaluating to `branch`. */
|
||||
predicate guardDirectlyControlsBlock(Guard guard, SsaInput::BasicBlock bb, GuardValue branch) {
|
||||
predicate guardDirectlyControlsBlock(Guard guard, BasicBlock bb, GuardValue branch) {
|
||||
Guards::guardControlsBlock(guard, bb, branch)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* See `shared/util/codeql/dataflow/test/InlineFlowTest.qll`
|
||||
*/
|
||||
|
||||
import ruby
|
||||
private import ruby
|
||||
private import codeql.Locations
|
||||
private import codeql.dataflow.test.InlineFlowTest
|
||||
private import codeql.ruby.dataflow.internal.DataFlowImplSpecific
|
||||
|
||||
@@ -16,7 +16,6 @@ import codeql.ruby.ast.internal.Constant
|
||||
import codeql.ruby.Concepts
|
||||
import codeql.ruby.frameworks.ActiveRecord
|
||||
private import codeql.ruby.TaintTracking
|
||||
private import codeql.ruby.CFG
|
||||
private import codeql.ruby.controlflow.internal.Guards as Guards
|
||||
|
||||
/** Gets the name of a built-in method that involves a loop operation. */
|
||||
@@ -42,7 +41,7 @@ class LoopingCall extends DataFlow::CallNode {
|
||||
|
||||
/** Holds if `ar` influences a guard that may control the execution of a loop. */
|
||||
predicate usedInLoopControlGuard(ActiveRecordInstance ar) {
|
||||
exists(DataFlow::Node insideGuard, CfgNodes::ExprCfgNode guard |
|
||||
exists(DataFlow::Node insideGuard, Cfg::CfgNodes::ExprCfgNode guard |
|
||||
// For a guard like `cond && ar`, the whole guard will not be tainted
|
||||
// so we need to look at the taint of the individual parts.
|
||||
insideGuard.asExpr().getExpr() = guard.getExpr().getAChild*()
|
||||
@@ -53,12 +52,12 @@ predicate usedInLoopControlGuard(ActiveRecordInstance ar) {
|
||||
}
|
||||
|
||||
/** Holds if `guard` controls `break` and `break` would break out of a loop. */
|
||||
predicate guardForLoopControl(CfgNodes::ExprCfgNode guard, CfgNodes::AstCfgNode break) {
|
||||
predicate guardForLoopControl(Cfg::CfgNodes::ExprCfgNode guard, Cfg::CfgNodes::AstCfgNode break) {
|
||||
Guards::guardControlsBlock(guard, break.getBasicBlock(), _) and
|
||||
(
|
||||
break.(CfgNodes::ExprNodes::MethodCallCfgNode).getMethodName() = "raise"
|
||||
break.(Cfg::CfgNodes::ExprNodes::MethodCallCfgNode).getMethodName() = "raise"
|
||||
or
|
||||
break instanceof CfgNodes::ReturningCfgNode
|
||||
break instanceof Cfg::CfgNodes::ReturningCfgNode
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import ruby
|
||||
import codeql.ruby.controlflow.ControlFlowGraph
|
||||
import codeql.ruby.controlflow.BasicBlocks
|
||||
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
* @kind path-problem
|
||||
*/
|
||||
|
||||
import codeql.ruby.AST
|
||||
import codeql.ruby.CFG
|
||||
import ruby
|
||||
import utils.test.InlineFlowTest
|
||||
import codeql.ruby.dataflow.BarrierGuards
|
||||
import PathGraph
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
private import codeql.controlflow.BasicBlock as BB
|
||||
private import codeql.Locations
|
||||
private import codeql.rust.controlflow.ControlFlowGraph as ControlFlowGraph
|
||||
private import internal.ControlFlowGraphImpl as CfgImpl
|
||||
private import CfgImpl::BasicBlocks as BasicBlocksImpl
|
||||
|
||||
final class BasicBlock = BasicBlocksImpl::BasicBlock;
|
||||
class BasicBlock = BasicBlocksImpl::BasicBlock;
|
||||
|
||||
final class EntryBasicBlock = BasicBlocksImpl::EntryBasicBlock;
|
||||
|
||||
@@ -14,3 +17,15 @@ final class ConditionBasicBlock = BasicBlocksImpl::ConditionBasicBlock;
|
||||
final class JoinBasicBlock = BasicBlocksImpl::JoinBasicBlock;
|
||||
|
||||
final class JoinPredecessorBasicBlock = BasicBlocksImpl::JoinPredecessorBasicBlock;
|
||||
|
||||
module Cfg implements BB::CfgSig<Location> {
|
||||
class ControlFlowNode = ControlFlowGraph::CfgNode;
|
||||
|
||||
class SuccessorType = ControlFlowGraph::SuccessorType;
|
||||
|
||||
class BasicBlock = BasicBlocksImpl::BasicBlock;
|
||||
|
||||
class EntryBasicBlock = BasicBlocksImpl::EntryBasicBlock;
|
||||
|
||||
predicate dominatingEdge = BasicBlocksImpl::dominatingEdge/2;
|
||||
}
|
||||
|
||||
@@ -844,6 +844,7 @@ module RustDataFlow implements InputSig<Location> {
|
||||
module VariableCapture {
|
||||
private import codeql.rust.internal.CachedStages
|
||||
private import codeql.dataflow.VariableCapture as SharedVariableCapture
|
||||
private import codeql.rust.controlflow.BasicBlocks as BasicBlocks
|
||||
|
||||
private predicate closureFlowStep(ExprCfgNode e1, ExprCfgNode e2) {
|
||||
Stages::DataFlowStage::ref() and
|
||||
@@ -855,22 +856,13 @@ module VariableCapture {
|
||||
)
|
||||
}
|
||||
|
||||
private module CaptureInput implements SharedVariableCapture::InputSig<Location> {
|
||||
private module CaptureInput implements
|
||||
SharedVariableCapture::InputSig<Location, BasicBlocks::BasicBlock>
|
||||
{
|
||||
private import rust as Ast
|
||||
private import codeql.rust.controlflow.BasicBlocks as BasicBlocks
|
||||
private import codeql.rust.elements.Variable as Variable
|
||||
|
||||
class BasicBlock extends BasicBlocks::BasicBlock {
|
||||
Callable getEnclosingCallable() { result = this.getScope() }
|
||||
}
|
||||
|
||||
class ControlFlowNode = CfgNode;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) {
|
||||
result = bb.getImmediateDominator()
|
||||
}
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
Callable basicBlockGetEnclosingCallable(BasicBlocks::BasicBlock bb) { result = bb.getScope() }
|
||||
|
||||
class CapturedVariable extends Variable {
|
||||
CapturedVariable() { this.isCaptured() }
|
||||
@@ -887,7 +879,7 @@ module VariableCapture {
|
||||
}
|
||||
|
||||
class Expr extends CfgNode {
|
||||
predicate hasCfgNode(BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
predicate hasCfgNode(BasicBlocks::BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
}
|
||||
|
||||
class VariableWrite extends Expr {
|
||||
@@ -949,7 +941,7 @@ module VariableCapture {
|
||||
|
||||
class CapturedVariable = CaptureInput::CapturedVariable;
|
||||
|
||||
module Flow = SharedVariableCapture::Flow<Location, CaptureInput>;
|
||||
module Flow = SharedVariableCapture::Flow<Location, BasicBlocks::Cfg, CaptureInput>;
|
||||
|
||||
private Flow::ClosureNode asClosureNode(Node n) {
|
||||
result = n.(CaptureNode).getSynthesizedCaptureNode()
|
||||
|
||||
@@ -54,15 +54,7 @@ private predicate variableReadCertain(BasicBlock bb, int i, VariableAccess va, V
|
||||
)
|
||||
}
|
||||
|
||||
module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||
class BasicBlock = BasicBlocks::BasicBlock;
|
||||
|
||||
class ControlFlowNode = CfgNode;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() }
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
module SsaInput implements SsaImplCommon::InputSig<Location, BasicBlock> {
|
||||
class SourceVariable = Variable;
|
||||
|
||||
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
@@ -91,7 +83,7 @@ module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||
}
|
||||
}
|
||||
|
||||
import SsaImplCommon::Make<Location, SsaInput> as Impl
|
||||
import SsaImplCommon::Make<Location, BasicBlocks::Cfg, SsaInput> as Impl
|
||||
|
||||
class Definition = Impl::Definition;
|
||||
|
||||
@@ -324,7 +316,7 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu
|
||||
private import codeql.util.Boolean
|
||||
|
||||
class Expr extends CfgNodes::AstCfgNode {
|
||||
predicate hasCfgNode(SsaInput::BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
predicate hasCfgNode(BasicBlock bb, int i) { this = bb.getNode(i) }
|
||||
}
|
||||
|
||||
Expr getARead(Definition def) { result = Cached::getARead(def) }
|
||||
@@ -357,9 +349,7 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu
|
||||
* Holds if the evaluation of this guard to `branch` corresponds to the edge
|
||||
* from `bb1` to `bb2`.
|
||||
*/
|
||||
predicate hasValueBranchEdge(
|
||||
SsaInput::BasicBlock bb1, SsaInput::BasicBlock bb2, GuardValue branch
|
||||
) {
|
||||
predicate hasValueBranchEdge(BasicBlock bb1, BasicBlock bb2, GuardValue branch) {
|
||||
exists(Cfg::ConditionalSuccessor s |
|
||||
this = bb1.getANode() and
|
||||
bb2 = bb1.getASuccessor(s) and
|
||||
@@ -372,15 +362,13 @@ private module DataFlowIntegrationInput implements Impl::DataFlowIntegrationInpu
|
||||
* branch edge from `bb1` to `bb2`. That is, following the edge from
|
||||
* `bb1` to `bb2` implies that this guard evaluated to `branch`.
|
||||
*/
|
||||
predicate valueControlsBranchEdge(
|
||||
SsaInput::BasicBlock bb1, SsaInput::BasicBlock bb2, GuardValue branch
|
||||
) {
|
||||
predicate valueControlsBranchEdge(BasicBlock bb1, BasicBlock bb2, GuardValue branch) {
|
||||
this.hasValueBranchEdge(bb1, bb2, branch)
|
||||
}
|
||||
}
|
||||
|
||||
/** Holds if the guard `guard` controls block `bb` upon evaluating to `branch`. */
|
||||
predicate guardDirectlyControlsBlock(Guard guard, SsaInput::BasicBlock bb, GuardValue branch) {
|
||||
predicate guardDirectlyControlsBlock(Guard guard, BasicBlock bb, GuardValue branch) {
|
||||
exists(ConditionBasicBlock conditionBlock, ConditionalSuccessor s |
|
||||
guard = conditionBlock.getLastNode() and
|
||||
s.getValue() = branch and
|
||||
|
||||
@@ -12,7 +12,11 @@ private import codeql.util.Location
|
||||
|
||||
/** Provides the language-specific input specification. */
|
||||
signature module InputSig<LocationSig Location> {
|
||||
class SuccessorType;
|
||||
/** The type of a control flow successor. */
|
||||
class SuccessorType {
|
||||
/** Gets a textual representation of this successor type. */
|
||||
string toString();
|
||||
}
|
||||
|
||||
/** Hold if `t` represents a conditional successor type. */
|
||||
predicate successorTypeIsCondition(SuccessorType t);
|
||||
@@ -47,12 +51,137 @@ signature module InputSig<LocationSig Location> {
|
||||
predicate nodeIsPostDominanceExit(Node node);
|
||||
}
|
||||
|
||||
signature module CfgSig<LocationSig Location> {
|
||||
/** A control flow node. */
|
||||
class ControlFlowNode {
|
||||
/** Gets a textual representation of this control flow node. */
|
||||
string toString();
|
||||
|
||||
/** Gets the location of this control flow node. */
|
||||
Location getLocation();
|
||||
}
|
||||
|
||||
/** The type of a control flow successor. */
|
||||
class SuccessorType {
|
||||
/** Gets a textual representation of this successor type. */
|
||||
string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A basic block, that is, a maximal straight-line sequence of control flow nodes
|
||||
* without branches or joins.
|
||||
*/
|
||||
class BasicBlock {
|
||||
/** Gets a textual representation of this basic block. */
|
||||
string toString();
|
||||
|
||||
/** Gets the location of this basic block. */
|
||||
Location getLocation();
|
||||
|
||||
/** Gets the control flow node at a specific (zero-indexed) position in this basic block. */
|
||||
ControlFlowNode getNode(int pos);
|
||||
|
||||
/** Gets the last control flow node in this basic block. */
|
||||
ControlFlowNode getLastNode();
|
||||
|
||||
/** Gets the length of this basic block. */
|
||||
int length();
|
||||
|
||||
/** Gets an immediate successor of this basic block, if any. */
|
||||
BasicBlock getASuccessor();
|
||||
|
||||
/** Gets an immediate successor of this basic block of a given type, if any. */
|
||||
BasicBlock getASuccessor(SuccessorType t);
|
||||
|
||||
/**
|
||||
* Holds if this basic block strictly dominates basic block `bb`.
|
||||
*
|
||||
* That is, all paths reaching `bb` from the entry point basic block must
|
||||
* go through this basic block and this basic block is different from `bb`.
|
||||
*/
|
||||
predicate strictlyDominates(BasicBlock bb);
|
||||
|
||||
/**
|
||||
* Holds if this basic block dominates basic block `bb`.
|
||||
*
|
||||
* That is, all paths reaching `bb` from the entry point basic block must
|
||||
* go through this basic block.
|
||||
*/
|
||||
predicate dominates(BasicBlock bb);
|
||||
|
||||
/**
|
||||
* Holds if `df` is in the dominance frontier of this basic block. That is,
|
||||
* this basic block dominates a predecessor of `df`, but does not dominate
|
||||
* `df` itself. I.e., it is equivaluent to:
|
||||
* ```
|
||||
* this.dominates(df.getAPredecessor()) and not this.strictlyDominates(df)
|
||||
* ```
|
||||
*/
|
||||
predicate inDominanceFrontier(BasicBlock df);
|
||||
|
||||
/**
|
||||
* Gets the basic block that immediately dominates this basic block, if any.
|
||||
*
|
||||
* That is, the result is the unique basic block satisfying:
|
||||
* 1. The result strictly dominates this basic block.
|
||||
* 2. There exists no other basic block that is strictly dominated by the
|
||||
* result and which strictly dominates this basic block.
|
||||
*
|
||||
* All basic blocks, except entry basic blocks, have a unique immediate
|
||||
* dominator.
|
||||
*/
|
||||
BasicBlock getImmediateDominator();
|
||||
|
||||
/**
|
||||
* Holds if this basic block strictly post-dominates basic block `bb`.
|
||||
*
|
||||
* That is, all paths reaching a normal exit point basic block from basic
|
||||
* block `bb` must go through this basic block and this basic block is
|
||||
* different from `bb`.
|
||||
*/
|
||||
predicate strictlyPostDominates(BasicBlock bb);
|
||||
|
||||
/**
|
||||
* Holds if this basic block post-dominates basic block `bb`.
|
||||
*
|
||||
* That is, all paths reaching a normal exit point basic block from basic
|
||||
* block `bb` must go through this basic block.
|
||||
*/
|
||||
predicate postDominates(BasicBlock bb);
|
||||
}
|
||||
|
||||
/**
|
||||
* An entry basic block, that is, a basic block whose first node is
|
||||
* an entry node.
|
||||
*/
|
||||
class EntryBasicBlock extends BasicBlock;
|
||||
|
||||
/**
|
||||
* Holds if `bb1` has `bb2` as a direct successor and the edge between `bb1`
|
||||
* and `bb2` is a dominating edge.
|
||||
*
|
||||
* An edge `(bb1, bb2)` is dominating if there exists a basic block that can
|
||||
* only be reached from the entry block by going through `(bb1, bb2)`. This
|
||||
* implies that `(bb1, bb2)` dominates its endpoint `bb2`. I.e., `bb2` can
|
||||
* only be reached from the entry block by going via `(bb1, bb2)`.
|
||||
*
|
||||
* This is a necessary and sufficient condition for an edge to dominate some
|
||||
* block, and therefore `dominatingEdge(bb1, bb2) and bb2.dominates(bb3)`
|
||||
* means that the edge `(bb1, bb2)` dominates `bb3`.
|
||||
*/
|
||||
predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a basic block construction on top of a control flow graph.
|
||||
*/
|
||||
module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
module Make<LocationSig Location, InputSig<Location> Input> implements CfgSig<Location> {
|
||||
private import Input
|
||||
|
||||
class ControlFlowNode = Input::Node;
|
||||
|
||||
class SuccessorType = Input::SuccessorType;
|
||||
|
||||
/**
|
||||
* A basic block, that is, a maximal straight-line sequence of control flow nodes
|
||||
* without branches or joins.
|
||||
@@ -239,6 +368,10 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
string toString() { result = this.getFirstNode().toString() }
|
||||
}
|
||||
|
||||
class EntryBasicBlock extends BasicBlock {
|
||||
EntryBasicBlock() { nodeIsDominanceEntry(this.getFirstNode()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bb1` has `bb2` as a direct successor and the edge between `bb1`
|
||||
* and `bb2` is a dominating edge.
|
||||
@@ -343,14 +476,14 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
cached
|
||||
Node getNode(BasicBlock bb, int pos) { bbIndex(bb.getFirstNode(), result, pos) }
|
||||
|
||||
/** Holds if `bb` is an entry basic block. */
|
||||
private predicate entryBB(BasicBlock bb) { nodeIsDominanceEntry(bb.getFirstNode()) }
|
||||
|
||||
cached
|
||||
predicate bbSuccessor(BasicBlock bb1, BasicBlock bb2, SuccessorType t) {
|
||||
bb2.getFirstNode() = nodeGetASuccessor(bb1.getLastNode(), t)
|
||||
}
|
||||
|
||||
/** Holds if `bb` is an entry basic block. */
|
||||
private predicate entryBlock(EntryBasicBlock bb) { any() }
|
||||
|
||||
/**
|
||||
* Holds if the first node of basic block `succ` is a control flow
|
||||
* successor of the last node of basic block `pred`.
|
||||
@@ -360,7 +493,7 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
/** Holds if `dom` is an immediate dominator of `bb`. */
|
||||
cached
|
||||
predicate bbIDominates(BasicBlock dom, BasicBlock bb) =
|
||||
idominance(entryBB/1, succBB/2)(_, dom, bb)
|
||||
idominance(entryBlock/1, succBB/2)(_, dom, bb)
|
||||
|
||||
/** Holds if `pred` is a basic block predecessor of `succ`. */
|
||||
private predicate predBB(BasicBlock succ, BasicBlock pred) { succBB(pred, succ) }
|
||||
|
||||
@@ -1609,7 +1609,7 @@ module MakeWithSplitting<
|
||||
|
||||
private module BasicBlockImpl = BB::Make<Location, BasicBlockInputSig>;
|
||||
|
||||
final class BasicBlock = BasicBlockImpl::BasicBlock;
|
||||
class BasicBlock = BasicBlockImpl::BasicBlock;
|
||||
|
||||
predicate dominatingEdge = BasicBlockImpl::dominatingEdge/2;
|
||||
|
||||
|
||||
@@ -50,16 +50,14 @@
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import codeql.controlflow.BasicBlock as BB
|
||||
private import codeql.util.Boolean
|
||||
private import codeql.util.Location
|
||||
private import codeql.util.Unit
|
||||
|
||||
signature module InputSig<LocationSig Location> {
|
||||
class SuccessorType {
|
||||
/** Gets a textual representation of this successor type. */
|
||||
string toString();
|
||||
}
|
||||
signature class TypSig;
|
||||
|
||||
signature module SuccessorTypesSig<TypSig SuccessorType> {
|
||||
class ExceptionSuccessor extends SuccessorType;
|
||||
|
||||
class ConditionalSuccessor extends SuccessorType {
|
||||
@@ -70,61 +68,12 @@ signature module InputSig<LocationSig Location> {
|
||||
class BooleanSuccessor extends ConditionalSuccessor;
|
||||
|
||||
class NullnessSuccessor extends ConditionalSuccessor;
|
||||
}
|
||||
|
||||
/** A control flow node. */
|
||||
class ControlFlowNode {
|
||||
/** Gets a textual representation of this control flow node. */
|
||||
string toString();
|
||||
|
||||
/** Gets the location of this control flow node. */
|
||||
Location getLocation();
|
||||
}
|
||||
|
||||
signature module InputSig<LocationSig Location, TypSig ControlFlowNode, TypSig BasicBlock> {
|
||||
/** A control flow node indicating normal termination of a callable. */
|
||||
class NormalExitNode extends ControlFlowNode;
|
||||
|
||||
/**
|
||||
* A basic block, that is, a maximal straight-line sequence of control flow nodes
|
||||
* without branches or joins.
|
||||
*/
|
||||
class BasicBlock {
|
||||
/** Gets a textual representation of this basic block. */
|
||||
string toString();
|
||||
|
||||
/** Gets the `i`th node in this basic block. */
|
||||
ControlFlowNode getNode(int i);
|
||||
|
||||
/** Gets the last control flow node in this basic block. */
|
||||
ControlFlowNode getLastNode();
|
||||
|
||||
/** Gets the length of this basic block. */
|
||||
int length();
|
||||
|
||||
/** Gets the location of this basic block. */
|
||||
Location getLocation();
|
||||
|
||||
BasicBlock getASuccessor(SuccessorType t);
|
||||
|
||||
predicate dominates(BasicBlock bb);
|
||||
|
||||
predicate strictlyDominates(BasicBlock bb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bb1` has `bb2` as a direct successor and the edge between `bb1`
|
||||
* and `bb2` is a dominating edge.
|
||||
*
|
||||
* An edge `(bb1, bb2)` is dominating if there exists a basic block that can
|
||||
* only be reached from the entry block by going through `(bb1, bb2)`. This
|
||||
* implies that `(bb1, bb2)` dominates its endpoint `bb2`. I.e., `bb2` can
|
||||
* only be reached from the entry block by going via `(bb1, bb2)`.
|
||||
*
|
||||
* This is a necessary and sufficient condition for an edge to dominate some
|
||||
* block, and therefore `dominatingEdge(bb1, bb2) and bb2.dominates(bb3)`
|
||||
* means that the edge `(bb1, bb2)` dominates `bb3`.
|
||||
*/
|
||||
predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2);
|
||||
|
||||
class AstNode {
|
||||
/** Gets a textual representation of this AST node. */
|
||||
string toString();
|
||||
@@ -254,7 +203,15 @@ signature module InputSig<LocationSig Location> {
|
||||
}
|
||||
|
||||
/** Provides guards-related predicates and classes. */
|
||||
module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
module Make<
|
||||
LocationSig Location, BB::CfgSig<Location> Cfg,
|
||||
SuccessorTypesSig<Cfg::SuccessorType> SuccessorTypes,
|
||||
InputSig<Location, Cfg::ControlFlowNode, Cfg::BasicBlock> Input>
|
||||
{
|
||||
private module Cfg_ = Cfg;
|
||||
|
||||
private import Cfg_
|
||||
private import SuccessorTypes
|
||||
private import Input
|
||||
|
||||
private newtype TAbstractSingleValue =
|
||||
|
||||
@@ -8,66 +8,14 @@ module;
|
||||
private import codeql.util.Boolean
|
||||
private import codeql.util.Unit
|
||||
private import codeql.util.Location
|
||||
private import codeql.controlflow.BasicBlock as BB
|
||||
private import codeql.ssa.Ssa as Ssa
|
||||
|
||||
signature module InputSig<LocationSig Location> {
|
||||
/**
|
||||
* A basic block, that is, a maximal straight-line sequence of control flow nodes
|
||||
* without branches or joins.
|
||||
*/
|
||||
class BasicBlock {
|
||||
/** Gets a textual representation of this basic block. */
|
||||
string toString();
|
||||
signature class BasicBlockSig;
|
||||
|
||||
/** Gets the `i`th node in this basic block. */
|
||||
ControlFlowNode getNode(int i);
|
||||
|
||||
/** Gets the length of this basic block. */
|
||||
int length();
|
||||
|
||||
/** Gets the enclosing callable. */
|
||||
Callable getEnclosingCallable();
|
||||
|
||||
/** Gets the location of this basic block. */
|
||||
Location getLocation();
|
||||
}
|
||||
|
||||
/** A control flow node. */
|
||||
class ControlFlowNode {
|
||||
/** Gets a textual representation of this control flow node. */
|
||||
string toString();
|
||||
|
||||
/** Gets the location of this control flow node. */
|
||||
Location getLocation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the basic block that immediately dominates basic block `bb`, if any.
|
||||
*
|
||||
* That is, all paths reaching `bb` from some entry point basic block must go
|
||||
* through the result.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```csharp
|
||||
* int M(string s) {
|
||||
* if (s == null)
|
||||
* throw new ArgumentNullException(nameof(s));
|
||||
* return s.Length;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The basic block starting on line 2 is an immediate dominator of
|
||||
* the basic block on line 4 (all paths from the entry point of `M`
|
||||
* to `return s.Length;` must go through the null check.
|
||||
*/
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb);
|
||||
|
||||
/** Gets an immediate successor of basic block `bb`, if any. */
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb);
|
||||
|
||||
/** Holds if `bb` is a control-flow entry point. */
|
||||
default predicate entryBlock(BasicBlock bb) { not exists(getImmediateBasicBlockDominator(bb)) }
|
||||
signature module InputSig<LocationSig Location, BasicBlockSig BasicBlock> {
|
||||
/** Gets the enclosing callable of the basic block. */
|
||||
Callable basicBlockGetEnclosingCallable(BasicBlock bb);
|
||||
|
||||
/** A variable that is captured in a closure. */
|
||||
class CapturedVariable {
|
||||
@@ -153,7 +101,9 @@ signature module InputSig<LocationSig Location> {
|
||||
}
|
||||
}
|
||||
|
||||
signature module OutputSig<LocationSig Location, InputSig<Location> I> {
|
||||
signature module OutputSig<
|
||||
LocationSig Location, BasicBlockSig BasicBlock, InputSig<Location, BasicBlock> I>
|
||||
{
|
||||
/**
|
||||
* A data flow node that we need to reference in the step relations for
|
||||
* captured variables.
|
||||
@@ -255,9 +205,18 @@ signature module OutputSig<LocationSig Location, InputSig<Location> I> {
|
||||
* Constructs the type `ClosureNode` and associated step relations, which are
|
||||
* intended to be included in the data-flow node and step relations.
|
||||
*/
|
||||
module Flow<LocationSig Location, InputSig<Location> Input> implements OutputSig<Location, Input> {
|
||||
module Flow<
|
||||
LocationSig Location, BB::CfgSig<Location> Cfg, InputSig<Location, Cfg::BasicBlock> Input>
|
||||
implements OutputSig<Location, Cfg::BasicBlock, Input>
|
||||
{
|
||||
private import Input
|
||||
|
||||
final private class CfgBb = Cfg::BasicBlock;
|
||||
|
||||
private class BasicBlock extends CfgBb {
|
||||
Callable getEnclosingCallable() { result = basicBlockGetEnclosingCallable(this) }
|
||||
}
|
||||
|
||||
additional module ConsistencyChecks {
|
||||
final private class FinalExpr = Expr;
|
||||
|
||||
@@ -332,17 +291,17 @@ module Flow<LocationSig Location, InputSig<Location> Input> implements OutputSig
|
||||
|
||||
query predicate uniqueDominator(RelevantBasicBlock bb, string msg) {
|
||||
msg = "BasicBlock has multiple immediate dominators" and
|
||||
2 <= strictcount(getImmediateBasicBlockDominator(bb))
|
||||
2 <= strictcount(bb.getImmediateDominator())
|
||||
}
|
||||
|
||||
query predicate localDominator(RelevantBasicBlock bb, string msg) {
|
||||
msg = "BasicBlock has non-local dominator" and
|
||||
bb.getEnclosingCallable() != getImmediateBasicBlockDominator(bb).getEnclosingCallable()
|
||||
bb.getEnclosingCallable() != bb.getImmediateDominator().(BasicBlock).getEnclosingCallable()
|
||||
}
|
||||
|
||||
query predicate localSuccessor(RelevantBasicBlock bb, string msg) {
|
||||
msg = "BasicBlock has non-local successor" and
|
||||
bb.getEnclosingCallable() != getABasicBlockSuccessor(bb).getEnclosingCallable()
|
||||
bb.getEnclosingCallable() != bb.getASuccessor().(BasicBlock).getEnclosingCallable()
|
||||
}
|
||||
|
||||
query predicate uniqueDefiningScope(CapturedVariable v, string msg) {
|
||||
@@ -669,7 +628,7 @@ module Flow<LocationSig Location, InputSig<Location> Input> implements OutputSig
|
||||
/** Holds if `cc` needs a definition at the entry of its callable scope. */
|
||||
private predicate entryDef(CaptureContainer cc, BasicBlock bb, int i) {
|
||||
exists(Callable c |
|
||||
entryBlock(bb) and
|
||||
bb instanceof Cfg::EntryBasicBlock and
|
||||
pragma[only_bind_out](bb.getEnclosingCallable()) = c and
|
||||
i =
|
||||
min(int j |
|
||||
@@ -685,22 +644,10 @@ module Flow<LocationSig Location, InputSig<Location> Input> implements OutputSig
|
||||
)
|
||||
}
|
||||
|
||||
private module CaptureSsaInput implements Ssa::InputSig<Location> {
|
||||
final class BasicBlock = Input::BasicBlock;
|
||||
|
||||
final class ControlFlowNode = Input::ControlFlowNode;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) {
|
||||
result = Input::getImmediateBasicBlockDominator(bb)
|
||||
}
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) {
|
||||
result = Input::getABasicBlockSuccessor(bb)
|
||||
}
|
||||
|
||||
private module CaptureSsaInput implements Ssa::InputSig<Location, Cfg::BasicBlock> {
|
||||
class SourceVariable = CaptureContainer;
|
||||
|
||||
predicate variableWrite(BasicBlock bb, int i, SourceVariable cc, boolean certain) {
|
||||
predicate variableWrite(Cfg::BasicBlock bb, int i, SourceVariable cc, boolean certain) {
|
||||
Cached::ref() and
|
||||
(
|
||||
exists(CapturedVariable v | cc = TVariable(v) and captureWrite(v, bb, i, true, _))
|
||||
@@ -710,9 +657,9 @@ module Flow<LocationSig Location, InputSig<Location> Input> implements OutputSig
|
||||
certain = true
|
||||
}
|
||||
|
||||
predicate variableRead(BasicBlock bb, int i, SourceVariable cc, boolean certain) {
|
||||
predicate variableRead(Cfg::BasicBlock bb, int i, SourceVariable cc, boolean certain) {
|
||||
(
|
||||
synthThisQualifier(bb, i) and cc = TThis(bb.getEnclosingCallable())
|
||||
synthThisQualifier(bb, i) and cc = TThis(bb.(BasicBlock).getEnclosingCallable())
|
||||
or
|
||||
exists(CapturedVariable v | cc = TVariable(v) |
|
||||
captureRead(v, bb, i, true, _) or synthRead(v, bb, i, true, _)
|
||||
@@ -722,26 +669,30 @@ module Flow<LocationSig Location, InputSig<Location> Input> implements OutputSig
|
||||
}
|
||||
}
|
||||
|
||||
private module CaptureSsa = Ssa::Make<Location, CaptureSsaInput>;
|
||||
private module CaptureSsa = Ssa::Make<Location, Cfg, CaptureSsaInput>;
|
||||
|
||||
private module DataFlowIntegrationInput implements CaptureSsa::DataFlowIntegrationInputSig {
|
||||
private import codeql.util.Void
|
||||
|
||||
class Expr instanceof Input::ControlFlowNode {
|
||||
class Expr instanceof Cfg::ControlFlowNode {
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
predicate hasCfgNode(BasicBlock bb, int i) { bb.getNode(i) = this }
|
||||
predicate hasCfgNode(Cfg::BasicBlock bb, int i) { bb.getNode(i) = this }
|
||||
}
|
||||
|
||||
class GuardValue = Void;
|
||||
|
||||
class Guard extends Void {
|
||||
predicate hasValueBranchEdge(BasicBlock bb1, BasicBlock bb2, GuardValue val) { none() }
|
||||
predicate hasValueBranchEdge(Cfg::BasicBlock bb1, Cfg::BasicBlock bb2, GuardValue val) {
|
||||
none()
|
||||
}
|
||||
|
||||
predicate valueControlsBranchEdge(BasicBlock bb1, BasicBlock bb2, GuardValue val) { none() }
|
||||
predicate valueControlsBranchEdge(Cfg::BasicBlock bb1, Cfg::BasicBlock bb2, GuardValue val) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
predicate guardDirectlyControlsBlock(Guard guard, BasicBlock bb, GuardValue val) { none() }
|
||||
predicate guardDirectlyControlsBlock(Guard guard, Cfg::BasicBlock bb, GuardValue val) { none() }
|
||||
|
||||
predicate includeWriteDefsInFlowStep() { none() }
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ version: 2.0.14-dev
|
||||
groups: shared
|
||||
library: true
|
||||
dependencies:
|
||||
codeql/controlflow: ${workspace}
|
||||
codeql/ssa: ${workspace}
|
||||
codeql/typetracking: ${workspace}
|
||||
codeql/util: ${workspace}
|
||||
|
||||
@@ -5,63 +5,14 @@
|
||||
overlay[local?]
|
||||
module;
|
||||
|
||||
private import codeql.controlflow.BasicBlock as BB
|
||||
private import codeql.util.Location
|
||||
private import codeql.util.Unit
|
||||
|
||||
signature class BasicBlockSig;
|
||||
|
||||
/** Provides the input specification of the SSA implementation. */
|
||||
signature module InputSig<LocationSig Location> {
|
||||
/**
|
||||
* A basic block, that is, a maximal straight-line sequence of control flow nodes
|
||||
* without branches or joins.
|
||||
*/
|
||||
class BasicBlock {
|
||||
/** Gets a textual representation of this basic block. */
|
||||
string toString();
|
||||
|
||||
/** Gets the `i`th node in this basic block. */
|
||||
ControlFlowNode getNode(int i);
|
||||
|
||||
/** Gets the length of this basic block. */
|
||||
int length();
|
||||
|
||||
/** Gets the location of this basic block. */
|
||||
Location getLocation();
|
||||
}
|
||||
|
||||
/** A control flow node. */
|
||||
class ControlFlowNode {
|
||||
/** Gets a textual representation of this control flow node. */
|
||||
string toString();
|
||||
|
||||
/** Gets the location of this control flow node. */
|
||||
Location getLocation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the basic block that immediately dominates basic block `bb`, if any.
|
||||
*
|
||||
* That is, all paths reaching `bb` from some entry point basic block must go
|
||||
* through the result.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```csharp
|
||||
* int M(string s) {
|
||||
* if (s == null)
|
||||
* throw new ArgumentNullException(nameof(s));
|
||||
* return s.Length;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The basic block starting on line 2 is an immediate dominator of
|
||||
* the basic block on line 4 (all paths from the entry point of `M`
|
||||
* to `return s.Length;` must go through the null check.
|
||||
*/
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb);
|
||||
|
||||
/** Gets an immediate successor of basic block `bb`, if any. */
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb);
|
||||
|
||||
signature module InputSig<LocationSig Location, BasicBlockSig BasicBlock> {
|
||||
/** A variable that can be SSA converted. */
|
||||
class SourceVariable {
|
||||
/** Gets a textual representation of this variable. */
|
||||
@@ -108,12 +59,13 @@ signature module InputSig<LocationSig Location> {
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
* ```
|
||||
*/
|
||||
module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
module Make<
|
||||
LocationSig Location, BB::CfgSig<Location> Cfg, InputSig<Location, Cfg::BasicBlock> Input>
|
||||
{
|
||||
private import Cfg
|
||||
private import Input
|
||||
|
||||
private BasicBlock getABasicBlockPredecessor(BasicBlock bb) {
|
||||
getABasicBlockSuccessor(result) = bb
|
||||
}
|
||||
private BasicBlock getABasicBlockPredecessor(BasicBlock bb) { result.getASuccessor() = bb }
|
||||
|
||||
/**
|
||||
* A classification of variable references into reads and
|
||||
@@ -237,9 +189,7 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
/**
|
||||
* Holds if source variable `v` is live at the end of basic block `bb`.
|
||||
*/
|
||||
predicate liveAtExit(BasicBlock bb, SourceVariable v) {
|
||||
liveAtEntry(getABasicBlockSuccessor(bb), v)
|
||||
}
|
||||
predicate liveAtExit(BasicBlock bb, SourceVariable v) { liveAtEntry(bb.getASuccessor(), v) }
|
||||
|
||||
/**
|
||||
* Holds if variable `v` is live in basic block `bb` at rank `rnk`.
|
||||
@@ -270,25 +220,6 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
|
||||
private import Liveness
|
||||
|
||||
/**
|
||||
* Holds if `df` is in the dominance frontier of `bb`.
|
||||
*
|
||||
* This is equivalent to:
|
||||
*
|
||||
* ```ql
|
||||
* bb = getImmediateBasicBlockDominator*(getABasicBlockPredecessor(df)) and
|
||||
* not bb = getImmediateBasicBlockDominator+(df)
|
||||
* ```
|
||||
*/
|
||||
private predicate inDominanceFrontier(BasicBlock bb, BasicBlock df) {
|
||||
bb = getABasicBlockPredecessor(df) and not bb = getImmediateBasicBlockDominator(df)
|
||||
or
|
||||
exists(BasicBlock prev | inDominanceFrontier(prev, df) |
|
||||
bb = getImmediateBasicBlockDominator(prev) and
|
||||
not bb = getImmediateBasicBlockDominator(df)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bb` is in the dominance frontier of a block containing a
|
||||
* definition of `v`.
|
||||
@@ -297,7 +228,7 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
private predicate inDefDominanceFrontier(BasicBlock bb, SourceVariable v) {
|
||||
exists(BasicBlock defbb, Definition def |
|
||||
def.definesAt(v, defbb, _) and
|
||||
inDominanceFrontier(defbb, bb)
|
||||
defbb.inDominanceFrontier(bb)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -307,7 +238,7 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate inReadDominanceFrontier(BasicBlock bb, SourceVariable v) {
|
||||
exists(BasicBlock readbb | inDominanceFrontier(readbb, bb) |
|
||||
exists(BasicBlock readbb | readbb.inDominanceFrontier(bb) |
|
||||
ssaDefReachesRead(v, _, readbb, _) and
|
||||
variableRead(readbb, _, v, true) and
|
||||
not variableWrite(readbb, _, v, _)
|
||||
@@ -389,7 +320,7 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate liveThrough(BasicBlock idom, BasicBlock bb, SourceVariable v) {
|
||||
idom = getImmediateBasicBlockDominator(bb) and
|
||||
idom = bb.getImmediateDominator() and
|
||||
liveAtExit(bb, v) and
|
||||
not any(Definition def).definesAt(v, bb, _)
|
||||
}
|
||||
@@ -439,7 +370,7 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
ssaDefReachesReadWithinBlock(v, def, bb, i)
|
||||
or
|
||||
ssaRef(bb, i, v, Read()) and
|
||||
ssaDefReachesEndOfBlock(getImmediateBasicBlockDominator(bb), def, v) and
|
||||
ssaDefReachesEndOfBlock(bb.getImmediateDominator(), def, v) and
|
||||
not ssaDefReachesReadWithinBlock(v, _, bb, i)
|
||||
}
|
||||
|
||||
@@ -483,7 +414,7 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate liveThrough(BasicBlock idom, BasicBlock bb, SourceVariable v) {
|
||||
idom = getImmediateBasicBlockDominator(bb) and
|
||||
idom = bb.getImmediateDominator() and
|
||||
liveAtExit(bb, v) and
|
||||
not ssaRef(bb, _, v, _)
|
||||
}
|
||||
@@ -517,7 +448,7 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
bb1 = bb2 and
|
||||
refRank(bb1, i1, v, _) + 1 = refRank(bb2, i2, v, Read())
|
||||
or
|
||||
refReachesEndOfBlock(bb1, i1, getImmediateBasicBlockDominator(bb2), v) and
|
||||
refReachesEndOfBlock(bb1, i1, bb2.getImmediateDominator(), v) and
|
||||
1 = refRank(bb2, i2, v, Read())
|
||||
}
|
||||
|
||||
@@ -808,12 +739,12 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
DefinitionExt def, SourceVariable v, BasicBlock bb1, BasicBlock bb2
|
||||
) {
|
||||
defOccursInBlock(def, bb1, v, _) and
|
||||
bb2 = getABasicBlockSuccessor(bb1)
|
||||
bb2 = bb1.getASuccessor()
|
||||
or
|
||||
exists(BasicBlock mid |
|
||||
varBlockReachesExt(def, v, bb1, mid) and
|
||||
ssaDefReachesThroughBlock(def, mid) and
|
||||
bb2 = getABasicBlockSuccessor(mid)
|
||||
bb2 = mid.getASuccessor()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -943,7 +874,7 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
// the node. If two definitions dominate a node then one must dominate the
|
||||
// other, so therefore the definition of _closest_ is given by the dominator
|
||||
// tree. Thus, reaching definitions can be calculated in terms of dominance.
|
||||
ssaDefReachesEndOfBlockExt0(getImmediateBasicBlockDominator(bb), def, pragma[only_bind_into](v)) and
|
||||
ssaDefReachesEndOfBlockExt0(bb.getImmediateDominator(), def, pragma[only_bind_into](v)) and
|
||||
liveThroughExt(bb, pragma[only_bind_into](v))
|
||||
}
|
||||
|
||||
@@ -1150,7 +1081,7 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
predicate uncertainWriteDefinitionInput = SsaDefReachesNew::uncertainWriteDefinitionInput/2;
|
||||
|
||||
/** Holds if `bb` is a control-flow exit point. */
|
||||
private predicate exitBlock(BasicBlock bb) { not exists(getABasicBlockSuccessor(bb)) }
|
||||
private predicate exitBlock(BasicBlock bb) { not exists(bb.getASuccessor()) }
|
||||
|
||||
/**
|
||||
* NB: If this predicate is exposed, it should be cached.
|
||||
@@ -1418,7 +1349,7 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
or
|
||||
ssaDefReachesRead(v, def, bb, i) and
|
||||
not SsaDefReachesNew::ssaDefReachesReadWithinBlock(v, def, bb, i) and
|
||||
not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _)
|
||||
not def.definesAt(v, bb.getImmediateDominator*(), _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1667,7 +1598,7 @@ module Make<LocationSig Location, InputSig<Location> Input> {
|
||||
DfInput::keepAllPhiInputBackEdges() and
|
||||
exists(getAPhiInputDef(phi, input)) and
|
||||
phi.getBasicBlock() = bbPhi and
|
||||
getImmediateBasicBlockDominator+(input) = bbPhi
|
||||
input.getImmediateDominator+() = bbPhi
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -3,5 +3,6 @@ version: 2.0.6-dev
|
||||
groups: shared
|
||||
library: true
|
||||
dependencies:
|
||||
codeql/controlflow: ${workspace}
|
||||
codeql/util: ${workspace}
|
||||
warnOnImplicitThis: true
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
/** Provides classes representing basic blocks. */
|
||||
|
||||
private import swift
|
||||
private import ControlFlowGraph
|
||||
private import internal.ControlFlowGraphImpl as CfgImpl
|
||||
private import SuccessorTypes
|
||||
private import CfgImpl::BasicBlocks as BasicBlocksImpl
|
||||
private import codeql.controlflow.BasicBlock as BB
|
||||
|
||||
/**
|
||||
* A basic block, that is, a maximal straight-line sequence of control flow nodes
|
||||
@@ -111,3 +113,25 @@ final class ConditionBlock extends BasicBlock, BasicBlocksImpl::ConditionBasicBl
|
||||
super.edgeDominates(controlled, s)
|
||||
}
|
||||
}
|
||||
|
||||
private class BasicBlockAlias = BasicBlock;
|
||||
|
||||
private class EntryBasicBlockAlias = EntryBasicBlock;
|
||||
|
||||
private class ControlFlowNodeAlias = ControlFlowNode;
|
||||
|
||||
private class SuccessorTypeAlias = SuccessorType;
|
||||
|
||||
module Cfg implements BB::CfgSig<Location> {
|
||||
class ControlFlowNode = ControlFlowNodeAlias;
|
||||
|
||||
class SuccessorType = SuccessorTypeAlias;
|
||||
|
||||
class BasicBlock = BasicBlockAlias;
|
||||
|
||||
class EntryBasicBlock = EntryBasicBlockAlias;
|
||||
|
||||
predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) {
|
||||
BasicBlocksImpl::dominatingEdge(bb1, bb2)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,21 +6,10 @@ module Ssa {
|
||||
private import codeql.swift.controlflow.ControlFlowGraph
|
||||
private import codeql.swift.controlflow.BasicBlocks as BasicBlocks
|
||||
|
||||
private module SsaInput implements SsaImplCommon::InputSig<Location> {
|
||||
private module SsaInput implements SsaImplCommon::InputSig<Location, BasicBlocks::BasicBlock> {
|
||||
private import internal.DataFlowPrivate
|
||||
private import codeql.swift.controlflow.ControlFlowGraph as Cfg
|
||||
private import codeql.swift.controlflow.CfgNodes
|
||||
|
||||
class BasicBlock = BasicBlocks::BasicBlock;
|
||||
|
||||
class ControlFlowNode = Cfg::ControlFlowNode;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) {
|
||||
result = bb.getImmediateDominator()
|
||||
}
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
|
||||
|
||||
private newtype TSourceVariable =
|
||||
TNormalSourceVariable(VarDecl v) or
|
||||
TKeyPathSourceVariable(EntryNode entry) { entry.getScope() instanceof KeyPathExpr }
|
||||
@@ -61,7 +50,7 @@ module Ssa {
|
||||
override EntryNode asKeyPath() { result = enter }
|
||||
}
|
||||
|
||||
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
predicate variableWrite(BasicBlocks::BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
exists(AssignExpr assign |
|
||||
bb.getNode(i).getNode().asAstNode() = assign and
|
||||
assign.getDest() = v.getAnAccess() and
|
||||
@@ -99,7 +88,7 @@ module Ssa {
|
||||
)
|
||||
}
|
||||
|
||||
predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
predicate variableRead(BasicBlocks::BasicBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
exists(DeclRefExpr ref |
|
||||
not isLValue(ref) and
|
||||
bb.getNode(i).getNode().asAstNode() = ref and
|
||||
@@ -133,7 +122,7 @@ module Ssa {
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*/
|
||||
module SsaImpl = SsaImplCommon::Make<Location, SsaInput>;
|
||||
module SsaImpl = SsaImplCommon::Make<Location, BasicBlocks::Cfg, SsaInput>;
|
||||
|
||||
cached
|
||||
class Definition extends SsaImpl::Definition {
|
||||
@@ -142,7 +131,7 @@ module Ssa {
|
||||
|
||||
cached
|
||||
ControlFlowNode getARead() {
|
||||
exists(SsaInput::SourceVariable v, SsaInput::BasicBlock bb, int i |
|
||||
exists(SsaInput::SourceVariable v, BasicBlocks::BasicBlock bb, int i |
|
||||
SsaImpl::ssaDefReachesRead(v, this, bb, i) and
|
||||
SsaInput::variableRead(bb, i, v, true) and
|
||||
result = bb.getNode(i)
|
||||
@@ -151,7 +140,7 @@ module Ssa {
|
||||
|
||||
cached
|
||||
ControlFlowNode getAFirstRead() {
|
||||
exists(SsaInput::BasicBlock bb, int i |
|
||||
exists(BasicBlocks::BasicBlock bb, int i |
|
||||
SsaImpl::firstUse(this, bb, i, true) and
|
||||
result = bb.getNode(i)
|
||||
)
|
||||
@@ -160,7 +149,7 @@ module Ssa {
|
||||
cached
|
||||
predicate adjacentReadPair(ControlFlowNode read1, ControlFlowNode read2) {
|
||||
read1 = this.getARead() and
|
||||
exists(SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2 |
|
||||
exists(BasicBlocks::BasicBlock bb1, int i1, BasicBlocks::BasicBlock bb2, int i2 |
|
||||
read1 = bb1.getNode(i1) and
|
||||
SsaImpl::adjacentUseUse(bb1, i1, bb2, i2, _, true) and
|
||||
read2 = bb2.getNode(i2)
|
||||
@@ -168,7 +157,7 @@ module Ssa {
|
||||
}
|
||||
|
||||
cached
|
||||
deprecated predicate lastRefRedef(SsaInput::BasicBlock bb, int i, Definition next) {
|
||||
deprecated predicate lastRefRedef(BasicBlocks::BasicBlock bb, int i, Definition next) {
|
||||
SsaImpl::lastRefRedef(this, bb, i, next)
|
||||
}
|
||||
}
|
||||
@@ -177,7 +166,7 @@ module Ssa {
|
||||
class WriteDefinition extends Definition, SsaImpl::WriteDefinition {
|
||||
cached
|
||||
override Location getLocation() {
|
||||
exists(SsaInput::BasicBlock bb, int i |
|
||||
exists(BasicBlocks::BasicBlock bb, int i |
|
||||
this.definesAt(_, bb, i) and
|
||||
result = bb.getNode(i).getLocation()
|
||||
)
|
||||
@@ -189,19 +178,19 @@ module Ssa {
|
||||
*/
|
||||
cached
|
||||
predicate assigns(CfgNode value) {
|
||||
exists(AssignExpr a, SsaInput::BasicBlock bb, int i |
|
||||
exists(AssignExpr a, BasicBlocks::BasicBlock bb, int i |
|
||||
this.definesAt(_, bb, i) and
|
||||
a = bb.getNode(i).getNode().asAstNode() and
|
||||
value.getNode().asAstNode() = a.getSource()
|
||||
)
|
||||
or
|
||||
exists(SsaInput::BasicBlock bb, int blockIndex, NamedPattern np |
|
||||
exists(BasicBlocks::BasicBlock bb, int blockIndex, NamedPattern np |
|
||||
this.definesAt(_, bb, blockIndex) and
|
||||
np = bb.getNode(blockIndex).getNode().asAstNode() and
|
||||
value.getNode().asAstNode() = np
|
||||
)
|
||||
or
|
||||
exists(SsaInput::BasicBlock bb, int blockIndex, ConditionElement ce, Expr init |
|
||||
exists(BasicBlocks::BasicBlock bb, int blockIndex, ConditionElement ce, Expr init |
|
||||
this.definesAt(_, bb, blockIndex) and
|
||||
ce.getPattern() = bb.getNode(blockIndex).getNode().asAstNode() and
|
||||
init = ce.getInitializer() and
|
||||
@@ -216,14 +205,14 @@ module Ssa {
|
||||
class PhiDefinition extends Definition, SsaImpl::PhiNode {
|
||||
cached
|
||||
override Location getLocation() {
|
||||
exists(SsaInput::BasicBlock bb |
|
||||
exists(BasicBlocks::BasicBlock bb |
|
||||
this.definesAt(_, bb, _) and
|
||||
result = bb.getLocation()
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Definition getPhiInput(SsaInput::BasicBlock bb) {
|
||||
Definition getPhiInput(BasicBlocks::BasicBlock bb) {
|
||||
SsaImpl::phiHasInputFromBlock(this, result, bb)
|
||||
}
|
||||
|
||||
|
||||
@@ -882,30 +882,11 @@ private predicate closureFlowStep(CaptureInput::Expr e1, CaptureInput::Expr e2)
|
||||
e2.(Pattern).getImmediateMatchingExpr() = e1
|
||||
}
|
||||
|
||||
private module CaptureInput implements VariableCapture::InputSig<Location> {
|
||||
private module CaptureInput implements VariableCapture::InputSig<Location, BasicBlock> {
|
||||
private import swift as S
|
||||
private import codeql.swift.controlflow.ControlFlowGraph as Cfg
|
||||
private import codeql.swift.controlflow.BasicBlocks as B
|
||||
|
||||
class BasicBlock instanceof B::BasicBlock {
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
ControlFlowNode getNode(int i) { result = super.getNode(i) }
|
||||
|
||||
int length() { result = super.length() }
|
||||
|
||||
Callable getEnclosingCallable() { result = super.getScope() }
|
||||
|
||||
Location getLocation() { result = super.getLocation() }
|
||||
}
|
||||
|
||||
class ControlFlowNode = Cfg::ControlFlowNode;
|
||||
|
||||
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) {
|
||||
result.(B::BasicBlock).immediatelyDominates(bb)
|
||||
}
|
||||
|
||||
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.(B::BasicBlock).getASuccessor() }
|
||||
Callable basicBlockGetEnclosingCallable(BasicBlock bb) { result = bb.getScope() }
|
||||
|
||||
class CapturedVariable instanceof S::VarDecl {
|
||||
CapturedVariable() {
|
||||
@@ -927,9 +908,7 @@ private module CaptureInput implements VariableCapture::InputSig<Location> {
|
||||
|
||||
Location getLocation() { result = super.getLocation() }
|
||||
|
||||
predicate hasCfgNode(BasicBlock bb, int i) {
|
||||
this = bb.(B::BasicBlock).getNode(i).getNode().asAstNode()
|
||||
}
|
||||
predicate hasCfgNode(BasicBlock bb, int i) { this = bb.getNode(i).getNode().asAstNode() }
|
||||
}
|
||||
|
||||
class VariableWrite extends Expr {
|
||||
@@ -1001,7 +980,7 @@ class CapturedVariable = CaptureInput::CapturedVariable;
|
||||
|
||||
class CapturedParameter = CaptureInput::CapturedParameter;
|
||||
|
||||
module CaptureFlow = VariableCapture::Flow<Location, CaptureInput>;
|
||||
module CaptureFlow = VariableCapture::Flow<Location, Cfg, CaptureInput>;
|
||||
|
||||
private CaptureFlow::ClosureNode asClosureNode(Node n) {
|
||||
result = n.(CaptureNode).getSynthesizedCaptureNode()
|
||||
|
||||
Reference in New Issue
Block a user