diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll index 3aa8994a4499..582391e81cc9 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll @@ -1880,9 +1880,7 @@ module IteratorFlow { } } - private module SsaInput implements SsaImpl::InputSig { - import Ssa::InputSigCommon - + private module SsaInput implements SsaImpl::InputSig { 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; + private module IteratorSsa = SsaImpl::Make; 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() } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImpl.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImpl.qll index 1cf45439d8b7..d48a48dfb445 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImpl.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImpl.qll @@ -891,15 +891,14 @@ private predicate baseSourceVariableIsGlobal( ) } -private module SsaInput implements Ssa::InputSig { - import InputSigCommon +private module SsaInput implements Ssa::InputSig { 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 { * 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; +private module SsaImpl = Ssa::Make; 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) } diff --git a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll index 617e2be8cc38..552f504b84b0 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll @@ -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() } -} diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll index 50395db47e77..ba5e562a71ef 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll @@ -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,47 @@ private predicate isEntryBlock(TIRBlock block) { block = MkIRBlock(any(EnterFunctionInstruction enter)) } +module IRCfg implements BB::CfgSig { + 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) } + } + + 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)) + } + + predicate entryBlock(BasicBlock bb) { isEntryBlock(bb) } +} + cached private module Cached { cached diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/IRBlock.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/IRBlock.qll index 50395db47e77..ba5e562a71ef 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/IRBlock.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/IRBlock.qll @@ -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,47 @@ private predicate isEntryBlock(TIRBlock block) { block = MkIRBlock(any(EnterFunctionInstruction enter)) } +module IRCfg implements BB::CfgSig { + 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) } + } + + 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)) + } + + predicate entryBlock(BasicBlock bb) { isEntryBlock(bb) } +} + cached private module Cached { cached diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll index 50395db47e77..ba5e562a71ef 100644 --- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll @@ -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,47 @@ private predicate isEntryBlock(TIRBlock block) { block = MkIRBlock(any(EnterFunctionInstruction enter)) } +module IRCfg implements BB::CfgSig { + 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) } + } + + 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)) + } + + predicate entryBlock(BasicBlock bb) { isEntryBlock(bb) } +} + cached private module Cached { cached diff --git a/csharp/ql/consistency-queries/CfgConsistency.ql b/csharp/ql/consistency-queries/CfgConsistency.ql index 3caf64f9aece..d7f0c091538d 100644 --- a/csharp/ql/consistency-queries/CfgConsistency.ql +++ b/csharp/ql/consistency-queries/CfgConsistency.ql @@ -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 ) } diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/BasicBlocks.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/BasicBlocks.qll index 9e548838adec..8271b0ac484f 100644 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/BasicBlocks.qll +++ b/csharp/ql/lib/semmle/code/csharp/controlflow/BasicBlocks.qll @@ -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,19 @@ final class ConditionBlock extends BasicBlock, BasicBlocksImpl::ConditionBasicBl super.edgeDominates(controlled, s) } } + +private class BasicBlockAlias = BasicBlock; + +module Cfg implements BB::CfgSig { + class ControlFlowNode = ControlFlow::Node; + + class SuccessorType = ControlFlow::SuccessorType; + + class BasicBlock = BasicBlockAlias; + + predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) { + BasicBlocksImpl::dominatingEdge(bb1, bb2) + } + + predicate entryBlock(BasicBlock bb) { bb instanceof EntryBasicBlock } +} diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowElement.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowElement.qll index 5649f43b8818..1cd09725b6e0 100644 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowElement.qll +++ b/csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowElement.qll @@ -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] diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/Guards.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/Guards.qll index 313fabc02356..2688472f71c3 100644 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/Guards.qll +++ b/csharp/ql/lib/semmle/code/csharp/controlflow/Guards.qll @@ -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) ) } diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll index 08debc21c0d0..774aa9958c8b 100644 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll +++ b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll @@ -13,6 +13,7 @@ import csharp private import Completion private import ControlFlowGraphImpl private import semmle.code.csharp.controlflow.ControlFlowGraph::ControlFlow as Cfg +private import codeql.controlflow.BasicBlock as BB private predicate startsBB(ControlFlowElement cfe) { not succ(_, cfe, _) and @@ -55,24 +56,34 @@ private predicate bbIDominates(PreBasicBlock dom, PreBasicBlock bb) = class PreBasicBlock extends ControlFlowElement { PreBasicBlock() { startsBB(this) } - PreBasicBlock getASuccessorByType(Cfg::SuccessorType t) { - succ(this.getLastElement(), result, any(Completion c | t = c.getAMatchingSuccessorType())) + PreBasicBlock getASuccessor(Cfg::SuccessorType t) { + succ(this.getLastNode(), result, any(Completion c | t = c.getAMatchingSuccessorType())) } - PreBasicBlock getASuccessor() { result = this.getASuccessorByType(_) } + deprecated PreBasicBlock getASuccessorByType(Cfg::SuccessorType t) { + result = this.getASuccessor(t) + } + + PreBasicBlock getASuccessor() { result = this.getASuccessor(_) } PreBasicBlock getAPredecessor() { result.getASuccessor() = this } - ControlFlowElement getElement(int pos) { bbIndex(this, result, pos) } + ControlFlowElement getNode(int pos) { bbIndex(this, result, pos) } - ControlFlowElement getAnElement() { result = this.getElement(_) } + deprecated ControlFlowElement getElement(int pos) { result = this.getNode(pos) } + + ControlFlowElement getAnElement() { result = this.getNode(_) } ControlFlowElement getFirstElement() { result = this } - ControlFlowElement getLastElement() { result = this.getElement(this.length() - 1) } + ControlFlowElement getLastNode() { result = this.getNode(this.length() - 1) } + + deprecated ControlFlowElement getLastElement() { result = this.getLastNode() } int length() { result = strictcount(this.getAnElement()) } + PreBasicBlock getImmediateDominator() { bbIDominates(result, this) } + predicate immediatelyDominates(PreBasicBlock bb) { bbIDominates(this, bb) } pragma[inline] @@ -84,45 +95,81 @@ class PreBasicBlock extends ControlFlowElement { or this.strictlyDominates(bb) } + + predicate inDominanceFrontier(PreBasicBlock df) { + this = df.getAPredecessor() and not bbIDominates(this, df) + or + exists(PreBasicBlock prev | prev.inDominanceFrontier(df) | + bbIDominates(this, prev) and + not bbIDominates(this, df) + ) + } + + /** Unsupported. Do not use. */ + predicate strictlyPostDominates(PreBasicBlock bb) { none() } + + /** Unsupported. Do not use. */ + predicate postDominates(PreBasicBlock bb) { + this.strictlyPostDominates(bb) or + this = bb + } } private Completion getConditionalCompletion(ConditionalCompletion cc) { result.getInnerCompletion() = cc } +pragma[nomagic] +private predicate conditionBlockImmediatelyControls( + ConditionBlock cond, PreBasicBlock succ, ConditionalCompletion cc +) { + exists(ControlFlowElement last, Completion c | + last = cond.getLastNode() and + c = getConditionalCompletion(cc) and + succ(last, succ, c) and + // In the pre-CFG, we need to account for case where one predecessor node has + // two edges to the same successor node. Assertion expressions are examples of + // such nodes. + not exists(Completion other | + succ(last, succ, other) and + other != c + ) and + forall(PreBasicBlock pred | pred = succ.getAPredecessor() and pred != cond | + succ.dominates(pred) + ) + ) +} + class ConditionBlock extends PreBasicBlock { ConditionBlock() { exists(Completion c | c = getConditionalCompletion(_) | - succ(this.getLastElement(), _, c) + succ(this.getLastNode(), _, c) or - scopeLast(_, this.getLastElement(), c) - ) - } - - pragma[nomagic] - private predicate immediatelyControls(PreBasicBlock succ, ConditionalCompletion cc) { - exists(ControlFlowElement last, Completion c | - last = this.getLastElement() and - c = getConditionalCompletion(cc) and - succ(last, succ, c) and - // In the pre-CFG, we need to account for case where one predecessor node has - // two edges to the same successor node. Assertion expressions are examples of - // such nodes. - not exists(Completion other | - succ(last, succ, other) and - other != c - ) and - forall(PreBasicBlock pred | pred = succ.getAPredecessor() and pred != this | - succ.dominates(pred) - ) + scopeLast(_, this.getLastNode(), c) ) } pragma[nomagic] predicate controls(PreBasicBlock controlled, Cfg::SuccessorTypes::ConditionalSuccessor s) { - exists(PreBasicBlock succ, ConditionalCompletion c | this.immediatelyControls(succ, c) | + exists(PreBasicBlock succ, ConditionalCompletion c | + conditionBlockImmediatelyControls(this, succ, c) + | succ.dominates(controlled) and s = c.getAMatchingSuccessorType() ) } } + +module PreCfg implements BB::CfgSig { + class ControlFlowNode = ControlFlowElement; + + class SuccessorType = Cfg::SuccessorType; + + class BasicBlock = PreBasicBlock; + + predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) { + conditionBlockImmediatelyControls(bb1, bb2, _) + } + + predicate entryBlock(BasicBlock bb) { entryBB(bb) } +} diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/PreSsa.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/PreSsa.qll index 6507bbbe04bf..ce9fdd406fd8 100644 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/PreSsa.qll +++ b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/PreSsa.qll @@ -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 { - 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 { + 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; + private module SsaImpl = SsaImplCommon::Make; 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) ) } } diff --git a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/Splitting.qll b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/Splitting.qll index b6efdfcf1eac..f57dd0703fce 100644 --- a/csharp/ql/lib/semmle/code/csharp/controlflow/internal/Splitting.qll +++ b/csharp/ql/lib/semmle/code/csharp/controlflow/internal/Splitting.qll @@ -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 diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/Nullness.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/Nullness.qll index 7e8ed0aadc04..352418779955 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/Nullness.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/Nullness.qll @@ -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() ) } diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/BaseSSA.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/BaseSSA.qll index ec1b5a0188e8..6e2d7d239f78 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/BaseSSA.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/BaseSSA.qll @@ -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 { + private module SsaInput implements SsaImplCommon::InputSig { 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; + private module SsaImpl = SsaImplCommon::Make; 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() diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll index ff2bf7092515..95d76059f76d 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll @@ -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 { + private module CaptureInput implements Shared::InputSig { 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; + module Flow = Shared::Flow; private Flow::ClosureNode asClosureNode(Node n) { result = n.(CaptureNode).getSynthesizedCaptureNode() diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImpl.qll index d1490c849163..7fbd179ace09 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImpl.qll @@ -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 { - 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 { class SourceVariable = Ssa::SourceVariable; /** @@ -25,7 +18,7 @@ private module SsaInput implements SsaImplCommon::InputSig { * * 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 { * * 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 { } } -import SsaImplCommon::Make as Impl +import SsaImplCommon::Make 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 ) } diff --git a/java/ql/lib/semmle/code/java/controlflow/BasicBlocks.qll b/java/ql/lib/semmle/code/java/controlflow/BasicBlocks.qll index e974f711ec45..9054debb04ee 100644 --- a/java/ql/lib/semmle/code/java/controlflow/BasicBlocks.qll +++ b/java/ql/lib/semmle/code/java/controlflow/BasicBlocks.qll @@ -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 { + class ControlFlowNode = BbImpl::ControlFlowNode; + + class SuccessorType = BbImpl::SuccessorType; + + class BasicBlock = BasicBlockAlias; + + predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) { BbImpl::dominatingEdge(bb1, bb2) } + + predicate entryBlock(BasicBlock bb) { BbImpl::entryBlock(bb) } +} diff --git a/java/ql/lib/semmle/code/java/controlflow/Guards.qll b/java/ql/lib/semmle/code/java/controlflow/Guards.qll index 778ebe6e8789..f7e82eaba914 100644 --- a/java/ql/lib/semmle/code/java/controlflow/Guards.qll +++ b/java/ql/lib/semmle/code/java/controlflow/Guards.qll @@ -139,19 +139,16 @@ private predicate isNonFallThroughPredecessor(SwitchCase sc, ControlFlowNode pre ) } -private module GuardsInput implements SharedGuards::InputSig { - private import java as J - private import semmle.code.java.dataflow.NullGuards as NullGuards +private module SuccessorTypes implements SharedGuards::SuccessorTypesSig { import SuccessorType +} - class ControlFlowNode = J::ControlFlowNode; +private module GuardsInput implements SharedGuards::InputSig { + private import java as J + private import semmle.code.java.dataflow.NullGuards as NullGuards 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; @@ -375,7 +372,7 @@ private module GuardsInput implements SharedGuards::InputSig { } } -private module GuardsImpl = SharedGuards::Make; +private module GuardsImpl = SharedGuards::Make; private module LogicInputCommon { private import semmle.code.java.dataflow.NullGuards as NullGuards diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll b/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll index 5c0fbb88d664..e50581c7e14c 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll @@ -157,17 +157,7 @@ private module BaseSsaImpl { private import BaseSsaImpl -private module SsaInput implements SsaImplCommon::InputSig { - 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 { class SourceVariable = BaseSsaSourceVariable; /** @@ -199,7 +189,7 @@ private module SsaInput implements SsaImplCommon::InputSig { } } -private module Impl = SsaImplCommon::Make; +private module Impl = SsaImplCommon::Make; private import Cached diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll index 8b9087ecbdc5..1721569e45a9 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/DataFlowPrivate.qll @@ -69,28 +69,10 @@ private predicate closureFlowStep(Expr e1, Expr e2) { ) } -private module CaptureInput implements VariableCapture::InputSig { +private module CaptureInput implements VariableCapture::InputSig { 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; +module CaptureFlow = VariableCapture::Flow; private CaptureFlow::ClosureNode asClosureNode(Node n) { result = n.(CaptureNode).getSynthesizedCaptureNode() diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/SsaImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/SsaImpl.qll index 51da69e9d64a..dc2cb7e7d00d 100644 --- a/java/ql/lib/semmle/code/java/dataflow/internal/SsaImpl.qll +++ b/java/ql/lib/semmle/code/java/dataflow/internal/SsaImpl.qll @@ -166,17 +166,7 @@ private predicate uncertainVariableUpdate(TrackedVar v, ControlFlowNode n, Basic uncertainVariableUpdate(v.getQualifier(), n, b, i) } -private module SsaInput implements SsaImplCommon::InputSig { - 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 { class SourceVariable = SsaSourceVariable; /** @@ -218,7 +208,7 @@ private module SsaInput implements SsaImplCommon::InputSig { } } -import SsaImplCommon::Make as Impl +import SsaImplCommon::Make as Impl final class Definition = Impl::Definition; diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/VariableCapture.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/VariableCapture.qll index 75f21bab38ac..2cbb54fc8f59 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/VariableCapture.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/VariableCapture.qll @@ -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 { +module VariableCaptureConfig implements InputSig { private js::Function getLambdaFromVariable(js::LocalVariable variable) { result.getVariable() = variable or @@ -106,10 +106,8 @@ module VariableCaptureConfig implements InputSig { ) } - 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 { 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::DbLocation 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 { } /** 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 { 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 { 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; +module VariableCaptureOutput = Flow; 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)) diff --git a/javascript/ql/lib/semmle/javascript/dataflow/internal/sharedlib/Ssa.qll b/javascript/ql/lib/semmle/javascript/dataflow/internal/sharedlib/Ssa.qll index eef4dc08318a..db00f3c096d0 100644 --- a/javascript/ql/lib/semmle/javascript/dataflow/internal/sharedlib/Ssa.qll +++ b/javascript/ql/lib/semmle/javascript/dataflow/internal/sharedlib/Ssa.qll @@ -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 { - class ControlFlowNode = js::ControlFlowNode; - - class BasicBlock = js::BasicBlock; - +module SsaConfig implements InputSig { class SourceVariable extends LocalVariableOrThis { SourceVariable() { not this.isCaptured() } } @@ -23,7 +19,7 @@ module SsaConfig implements InputSig { 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 { ) } - 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 +import Make 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 diff --git a/javascript/ql/lib/semmle/javascript/internal/BasicBlockInternal.qll b/javascript/ql/lib/semmle/javascript/internal/BasicBlockInternal.qll index c7ad2a1ada81..91d1016cf2a7 100644 --- a/javascript/ql/lib/semmle/javascript/internal/BasicBlockInternal.qll +++ b/javascript/ql/lib/semmle/javascript/internal/BasicBlockInternal.qll @@ -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. @@ -362,4 +363,48 @@ module Public { ) } } + + final private class FinalBasicBlock = BasicBlock; + + module Cfg implements BB::CfgSig { + 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) } + } + + 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)) + } + + predicate entryBlock(BasicBlock bb) { entryBB(bb) } + } } diff --git a/python/ql/lib/semmle/python/Flow.qll b/python/ql/lib/semmle/python/Flow.qll index 90633651f110..572bbebf1e1d 100644 --- a/python/ql/lib/semmle/python/Flow.qll +++ b/python/ql/lib/semmle/python/Flow.qll @@ -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,54 @@ 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 { + 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 + } + } + + 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)) + } + + predicate entryBlock(BasicBlock bb) { bb.getNode(0).isEntryNode() } +} diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/VariableCapture.qll b/python/ql/lib/semmle/python/dataflow/new/internal/VariableCapture.qll index 6cb80881e2a8..a7b3b9ceaebf 100644 --- a/python/ql/lib/semmle/python/dataflow/new/internal/VariableCapture.qll +++ b/python/ql/lib/semmle/python/dataflow/new/internal/VariableCapture.qll @@ -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 { +private module CaptureInput implements Shared::InputSig { private import python as PY additional class ExprCfgNode extends ControlFlowNode { @@ -23,24 +23,7 @@ private module CaptureInput implements Shared::InputSig { 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 { } 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 { 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; +module Flow = Shared::Flow; private Flow::ClosureNode asClosureNode(Node n) { result = n.(SynthCaptureNode).getSynthesizedCaptureNode() diff --git a/ruby/ql/lib/codeql/ruby/controlflow/BasicBlocks.qll b/ruby/ql/lib/codeql/ruby/controlflow/BasicBlocks.qll index 932533711984..c6d4b86b882f 100644 --- a/ruby/ql/lib/codeql/ruby/controlflow/BasicBlocks.qll +++ b/ruby/ql/lib/codeql/ruby/controlflow/BasicBlocks.qll @@ -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,21 @@ final class ConditionBlock extends BasicBlock, BasicBlocksImpl::ConditionBasicBl super.edgeDominates(controlled, s) } } + +private class BasicBlockAlias = BasicBlock; + +private class SuccessorTypeAlias = SuccessorType; + +module Cfg implements BB::CfgSig { + class ControlFlowNode = CfgNode; + + class SuccessorType = SuccessorTypeAlias; + + class BasicBlock = BasicBlockAlias; + + predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) { + BasicBlocksImpl::dominatingEdge(bb1, bb2) + } + + predicate entryBlock(BasicBlock bb) { bb instanceof EntryBasicBlock } +} diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll index 59fe0238c7ff..91408072ed7c 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll @@ -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 { + private module CaptureInput implements Shared::InputSig { 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; + module Flow = Shared::Flow; private Flow::ClosureNode asClosureNode(Node n) { result = n.(CaptureNode).getSynthesizedCaptureNode() diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImpl.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImpl.qll index fd1619b1c634..af5745f6fd3c 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImpl.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImpl.qll @@ -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 { - 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() } +private class BasicBlock = BasicBlocks::Cfg::BasicBlock; - BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() } +module SsaInput implements SsaImplCommon::InputSig { + private import codeql.ruby.controlflow.ControlFlowGraph as Cfg class SourceVariable = LocalVariable; @@ -66,7 +60,7 @@ module SsaInput implements SsaImplCommon::InputSig { } } -import SsaImplCommon::Make as Impl +import SsaImplCommon::Make 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) } } diff --git a/ruby/ql/lib/codeql/ruby/security/UnsafeShellCommandConstructionCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/UnsafeShellCommandConstructionCustomizations.qll index ee00d96b4f34..ad164f979b37 100644 --- a/ruby/ql/lib/codeql/ruby/security/UnsafeShellCommandConstructionCustomizations.qll +++ b/ruby/ql/lib/codeql/ruby/security/UnsafeShellCommandConstructionCustomizations.qll @@ -111,13 +111,10 @@ module UnsafeShellCommandConstruction { isUsedAsShellCommand(call, s) and ( this = call.getReceiver() and - not call.getReceiver().asExpr() instanceof Cfg::CfgNodes::ExprNodes::ArrayLiteralCfgNode + not call.getReceiver().asExpr() instanceof CfgNodes::ExprNodes::ArrayLiteralCfgNode or this.asExpr() = - call.getReceiver() - .asExpr() - .(Cfg::CfgNodes::ExprNodes::ArrayLiteralCfgNode) - .getAnArgument() + call.getReceiver().asExpr().(CfgNodes::ExprNodes::ArrayLiteralCfgNode).getAnArgument() ) } diff --git a/ruby/ql/lib/codeql/ruby/security/WeakSensitiveDataHashingCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/WeakSensitiveDataHashingCustomizations.qll index 92ba8492c5ac..50b31199114f 100644 --- a/ruby/ql/lib/codeql/ruby/security/WeakSensitiveDataHashingCustomizations.qll +++ b/ruby/ql/lib/codeql/ruby/security/WeakSensitiveDataHashingCustomizations.qll @@ -69,7 +69,7 @@ private module SensitiveDataSources { */ class SensitiveHashValueAccess extends SensitiveDataSource::Range instanceof SensitiveNode { SensitiveHashValueAccess() { - this.asExpr() instanceof Cfg::CfgNodes::ExprNodes::ElementReferenceCfgNode + this.asExpr() instanceof CfgNodes::ExprNodes::ElementReferenceCfgNode } override SensitiveDataClassification getClassification() { diff --git a/ruby/ql/lib/ruby.qll b/ruby/ql/lib/ruby.qll index 407d58220dca..0a0187dde3b8 100644 --- a/ruby/ql/lib/ruby.qll +++ b/ruby/ql/lib/ruby.qll @@ -3,5 +3,5 @@ */ import codeql.ruby.AST as Ast -import codeql.ruby.CFG as Cfg +import codeql.ruby.CFG import codeql.ruby.DataFlow // already defines its own wrapper module diff --git a/rust/ql/lib/codeql/rust/controlflow/BasicBlocks.qll b/rust/ql/lib/codeql/rust/controlflow/BasicBlocks.qll index 4a4b637f3d3d..03eac5e31be0 100644 --- a/rust/ql/lib/codeql/rust/controlflow/BasicBlocks.qll +++ b/rust/ql/lib/codeql/rust/controlflow/BasicBlocks.qll @@ -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 { + class ControlFlowNode = ControlFlowGraph::CfgNode; + + class SuccessorType = ControlFlowGraph::SuccessorType; + + class BasicBlock = BasicBlocksImpl::BasicBlock; + + predicate dominatingEdge = BasicBlocksImpl::dominatingEdge/2; + + predicate entryBlock(BasicBlock bb) { bb instanceof EntryBasicBlock } +} diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll index 727f14bb94ab..62fa0aa11bd5 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll @@ -844,6 +844,7 @@ module RustDataFlow implements InputSig { 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 { + private module CaptureInput implements + SharedVariableCapture::InputSig + { 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; + module Flow = SharedVariableCapture::Flow; private Flow::ClosureNode asClosureNode(Node n) { result = n.(CaptureNode).getSynthesizedCaptureNode() diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/SsaImpl.qll b/rust/ql/lib/codeql/rust/dataflow/internal/SsaImpl.qll index 9b6d254dec13..df0824fcdfc2 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/SsaImpl.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/SsaImpl.qll @@ -54,15 +54,7 @@ private predicate variableReadCertain(BasicBlock bb, int i, VariableAccess va, V ) } -module SsaInput implements SsaImplCommon::InputSig { - 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 { class SourceVariable = Variable; predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) { @@ -91,7 +83,7 @@ module SsaInput implements SsaImplCommon::InputSig { } } -import SsaImplCommon::Make as Impl +import SsaImplCommon::Make 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 diff --git a/shared/controlflow/codeql/controlflow/BasicBlock.qll b/shared/controlflow/codeql/controlflow/BasicBlock.qll index 132920e329fb..683182786bec 100644 --- a/shared/controlflow/codeql/controlflow/BasicBlock.qll +++ b/shared/controlflow/codeql/controlflow/BasicBlock.qll @@ -12,7 +12,11 @@ private import codeql.util.Location /** Provides the language-specific input specification. */ signature module InputSig { - 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,134 @@ signature module InputSig { predicate nodeIsPostDominanceExit(Node node); } +signature module CfgSig { + /** 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); + } + + /** + * 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); + + /** Holds if `bb` is an entry basic block. */ + predicate entryBlock(BasicBlock bb); +} + /** * Provides a basic block construction on top of a control flow graph. */ -module Make Input> { +module Make Input> implements CfgSig { 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. @@ -275,6 +401,9 @@ module Make Input> { forall(BasicBlock pred | pred = bb2.getAPredecessor() and pred != bb1 | bb2.dominates(pred)) } + /** Holds if `bb` is an entry basic block. */ + predicate entryBlock(BasicBlock bb) { nodeIsDominanceEntry(bb.getFirstNode()) } + cached private module Cached { private Node nodeGetAPredecessor(Node node, SuccessorType s) { @@ -343,9 +472,6 @@ module Make 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) @@ -360,7 +486,7 @@ module Make 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) } diff --git a/shared/controlflow/codeql/controlflow/Cfg.qll b/shared/controlflow/codeql/controlflow/Cfg.qll index 25796089ab50..6577a067175d 100644 --- a/shared/controlflow/codeql/controlflow/Cfg.qll +++ b/shared/controlflow/codeql/controlflow/Cfg.qll @@ -1609,7 +1609,7 @@ module MakeWithSplitting< private module BasicBlockImpl = BB::Make; - final class BasicBlock = BasicBlockImpl::BasicBlock; + class BasicBlock = BasicBlockImpl::BasicBlock; predicate dominatingEdge = BasicBlockImpl::dominatingEdge/2; diff --git a/shared/controlflow/codeql/controlflow/Guards.qll b/shared/controlflow/codeql/controlflow/Guards.qll index 917f95569edb..f39cb67b7e1a 100644 --- a/shared/controlflow/codeql/controlflow/Guards.qll +++ b/shared/controlflow/codeql/controlflow/Guards.qll @@ -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 { - class SuccessorType { - /** Gets a textual representation of this successor type. */ - string toString(); - } +signature class TypSig; +signature module SuccessorTypesSig { class ExceptionSuccessor extends SuccessorType; class ConditionalSuccessor extends SuccessorType { @@ -70,61 +68,12 @@ signature module InputSig { 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 { /** 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 { } /** Provides guards-related predicates and classes. */ -module Make Input> { +module Make< + LocationSig Location, BB::CfgSig Cfg, + SuccessorTypesSig SuccessorTypes, + InputSig Input> +{ + private module Cfg_ = Cfg; + + private import Cfg_ + private import SuccessorTypes private import Input private newtype TAbstractSingleValue = diff --git a/shared/dataflow/codeql/dataflow/VariableCapture.qll b/shared/dataflow/codeql/dataflow/VariableCapture.qll index 922391221a40..abfa942df289 100644 --- a/shared/dataflow/codeql/dataflow/VariableCapture.qll +++ b/shared/dataflow/codeql/dataflow/VariableCapture.qll @@ -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 { - /** - * 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 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(); +signature class BasicBlockSig; - /** 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 { + /** 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 { } } -signature module OutputSig I> { +signature module OutputSig< + LocationSig Location, BasicBlockSig BasicBlock, InputSig I> +{ /** * A data flow node that we need to reference in the step relations for * captured variables. @@ -255,9 +205,18 @@ signature module OutputSig 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 Input> implements OutputSig { +module Flow< + LocationSig Location, BB::CfgSig Cfg, InputSig Input> + implements OutputSig +{ 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 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 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 + Cfg::entryBlock(bb) and pragma[only_bind_out](bb.getEnclosingCallable()) = c and i = min(int j | @@ -685,22 +644,10 @@ module Flow Input> implements OutputSig ) } - private module CaptureSsaInput implements Ssa::InputSig { - 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 { 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 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 Input> implements OutputSig } } - private module CaptureSsa = Ssa::Make; + private module CaptureSsa = Ssa::Make; private module DataFlowIntegrationInput implements CaptureSsa::DataFlowIntegrationInputSig { private import codeql.util.Void - class Expr instanceof Input::ControlFlowNode { + class Expr instanceof Cfg::ControlFlowNode { string toString() { result = super.toString() } - predicate hasCfgNode(BasicBlock bb, int i) { bb.getNode(i) = this } + predicate hasCfgNode(Cfg::BasicBlock bb, int i) { bb.getNode(i) = this } } class GuardValue = Void; class Guard extends Void { - predicate hasValueBranchEdge(BasicBlock bb1, BasicBlock bb2, GuardValue val) { none() } + predicate hasValueBranchEdge(Cfg::BasicBlock bb1, Cfg::BasicBlock bb2, GuardValue val) { + none() + } - predicate valueControlsBranchEdge(BasicBlock bb1, BasicBlock bb2, GuardValue val) { none() } + predicate valueControlsBranchEdge(Cfg::BasicBlock bb1, Cfg::BasicBlock bb2, GuardValue val) { + none() + } } - predicate guardDirectlyControlsBlock(Guard guard, BasicBlock bb, GuardValue val) { none() } + predicate guardDirectlyControlsBlock(Guard guard, Cfg::BasicBlock bb, GuardValue val) { none() } predicate includeWriteDefsInFlowStep() { none() } diff --git a/shared/dataflow/qlpack.yml b/shared/dataflow/qlpack.yml index 20069450f228..7ad5bfbdfc36 100644 --- a/shared/dataflow/qlpack.yml +++ b/shared/dataflow/qlpack.yml @@ -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} diff --git a/shared/ssa/codeql/ssa/Ssa.qll b/shared/ssa/codeql/ssa/Ssa.qll index 2aa136ff7197..20a447f91a99 100644 --- a/shared/ssa/codeql/ssa/Ssa.qll +++ b/shared/ssa/codeql/ssa/Ssa.qll @@ -5,63 +5,14 @@ overlay[local?] module; +private import codeql.controlflow.BasicBlock as BB private import codeql.util.Location private import codeql.util.Unit -/** Provides the input specification of the SSA implementation. */ -signature module InputSig { - /** - * 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 class BasicBlockSig; +/** Provides the input specification of the SSA implementation. */ +signature module InputSig { /** A variable that can be SSA converted. */ class SourceVariable { /** Gets a textual representation of this variable. */ @@ -108,12 +59,13 @@ signature module InputSig { * NB: If this predicate is exposed, it should be cached. * ``` */ -module Make Input> { +module Make< + LocationSig Location, BB::CfgSig Cfg, InputSig 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 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 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 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 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 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 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 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 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 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 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 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 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 Input> { DfInput::keepAllPhiInputBackEdges() and exists(getAPhiInputDef(phi, input)) and phi.getBasicBlock() = bbPhi and - getImmediateBasicBlockDominator+(input) = bbPhi + input.getImmediateDominator+() = bbPhi ) } diff --git a/shared/ssa/qlpack.yml b/shared/ssa/qlpack.yml index 30858c2f029e..8a103c0ef102 100644 --- a/shared/ssa/qlpack.yml +++ b/shared/ssa/qlpack.yml @@ -3,5 +3,6 @@ version: 2.0.6-dev groups: shared library: true dependencies: + codeql/controlflow: ${workspace} codeql/util: ${workspace} warnOnImplicitThis: true diff --git a/swift/ql/lib/codeql/swift/controlflow/BasicBlocks.qll b/swift/ql/lib/codeql/swift/controlflow/BasicBlocks.qll index 160903fd8954..bc4c1641cb46 100644 --- a/swift/ql/lib/codeql/swift/controlflow/BasicBlocks.qll +++ b/swift/ql/lib/codeql/swift/controlflow/BasicBlocks.qll @@ -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,23 @@ final class ConditionBlock extends BasicBlock, BasicBlocksImpl::ConditionBasicBl super.edgeDominates(controlled, s) } } + +private class BasicBlockAlias = BasicBlock; + +private class ControlFlowNodeAlias = ControlFlowNode; + +private class SuccessorTypeAlias = SuccessorType; + +module Cfg implements BB::CfgSig { + class ControlFlowNode = ControlFlowNodeAlias; + + class SuccessorType = SuccessorTypeAlias; + + class BasicBlock = BasicBlockAlias; + + predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) { + BasicBlocksImpl::dominatingEdge(bb1, bb2) + } + + predicate entryBlock(BasicBlock bb) { bb instanceof EntryBasicBlock } +} diff --git a/swift/ql/lib/codeql/swift/dataflow/Ssa.qll b/swift/ql/lib/codeql/swift/dataflow/Ssa.qll index ed75a06e5349..4f0754ff5900 100644 --- a/swift/ql/lib/codeql/swift/dataflow/Ssa.qll +++ b/swift/ql/lib/codeql/swift/dataflow/Ssa.qll @@ -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 { + private module SsaInput implements SsaImplCommon::InputSig { 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; + module SsaImpl = SsaImplCommon::Make; 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) } diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll index 4849c5ac2355..9ea57c1ff062 100644 --- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll +++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll @@ -882,30 +882,11 @@ private predicate closureFlowStep(CaptureInput::Expr e1, CaptureInput::Expr e2) e2.(Pattern).getImmediateMatchingExpr() = e1 } -private module CaptureInput implements VariableCapture::InputSig { +private module CaptureInput implements VariableCapture::InputSig { 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 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; +module CaptureFlow = VariableCapture::Flow; private CaptureFlow::ClosureNode asClosureNode(Node n) { result = n.(CaptureNode).getSynthesizedCaptureNode()