Merge pull request #20253 from aschackmull/shared/basicblock-signature2

Shared: Add and use a signature for basic blocks
This commit is contained in:
Anders Schack-Mulligen
2025-09-01 12:39:33 +02:00
committed by GitHub
47 changed files with 825 additions and 657 deletions

View File

@@ -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()
}

View File

@@ -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)
}

View File

@@ -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() }
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
)
}

View File

@@ -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)
}
}

View File

@@ -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]

View File

@@ -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)
)
}

View File

@@ -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,25 +95,36 @@ 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
}
class ConditionBlock extends PreBasicBlock {
ConditionBlock() {
exists(Completion c | c = getConditionalCompletion(_) |
succ(this.getLastElement(), _, c)
or
scopeLast(_, this.getLastElement(), c)
)
}
pragma[nomagic]
private predicate immediatelyControls(PreBasicBlock succ, ConditionalCompletion cc) {
private predicate conditionBlockImmediatelyControls(
ConditionBlock cond, PreBasicBlock succ, ConditionalCompletion cc
) {
exists(ControlFlowElement last, Completion c |
last = this.getLastElement() and
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
@@ -112,17 +134,44 @@ class ConditionBlock extends PreBasicBlock {
succ(last, succ, other) and
other != c
) and
forall(PreBasicBlock pred | pred = succ.getAPredecessor() and pred != this |
forall(PreBasicBlock pred | pred = succ.getAPredecessor() and pred != cond |
succ.dominates(pred)
)
)
}
class ConditionBlock extends PreBasicBlock {
ConditionBlock() {
exists(Completion c | c = getConditionalCompletion(_) |
succ(this.getLastNode(), _, c)
or
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, _)
}
}

View File

@@ -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)
)
}
}

View File

@@ -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

View File

@@ -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()
)
}

View File

@@ -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()

View File

@@ -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()

View File

@@ -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
)
}

View File

@@ -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) }
}

View File

@@ -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

View File

@@ -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

View File

@@ -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()

View File

@@ -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;

View File

@@ -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))

View File

@@ -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

View File

@@ -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))
}
}
}

View File

@@ -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))
}
}

View File

@@ -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()

View File

@@ -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)
}
}

View File

@@ -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()

View File

@@ -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)
}
}

View File

@@ -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

View File

@@ -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
)
}

View File

@@ -1,4 +1,3 @@
import ruby
import codeql.ruby.controlflow.ControlFlowGraph
import codeql.ruby.controlflow.BasicBlocks

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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()

View File

@@ -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

View File

@@ -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) }

View File

@@ -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;

View File

@@ -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 =

View File

@@ -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 valueControlsBranchEdge(BasicBlock bb1, BasicBlock bb2, GuardValue val) { none() }
predicate hasValueBranchEdge(Cfg::BasicBlock bb1, Cfg::BasicBlock bb2, GuardValue val) {
none()
}
predicate guardDirectlyControlsBlock(Guard guard, BasicBlock bb, GuardValue val) { none() }
predicate valueControlsBranchEdge(Cfg::BasicBlock bb1, Cfg::BasicBlock bb2, GuardValue val) {
none()
}
}
predicate guardDirectlyControlsBlock(Guard guard, Cfg::BasicBlock bb, GuardValue val) { none() }
predicate includeWriteDefsInFlowStep() { none() }

View File

@@ -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}

View File

@@ -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
)
}

View File

@@ -3,5 +3,6 @@ version: 2.0.6-dev
groups: shared
library: true
dependencies:
codeql/controlflow: ${workspace}
codeql/util: ${workspace}
warnOnImplicitThis: true

View File

@@ -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)
}
}

View File

@@ -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)
}

View File

@@ -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()