From 3dd6b3fb69054537ebee3ac69e1121e2bd70dfe3 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Wed, 28 Jan 2026 14:52:57 +0000 Subject: [PATCH] Use shared basic blocks library --- .../lib/semmle/go/controlflow/BasicBlocks.qll | 199 ++++-------------- .../go/controlflow/ControlFlowGraph.qll | 2 + go/ql/lib/semmle/go/dataflow/SsaImpl.qll | 2 +- 3 files changed, 39 insertions(+), 164 deletions(-) diff --git a/go/ql/lib/semmle/go/controlflow/BasicBlocks.qll b/go/ql/lib/semmle/go/controlflow/BasicBlocks.qll index 8380c6d6d5d..232b6a5e00b 100644 --- a/go/ql/lib/semmle/go/controlflow/BasicBlocks.qll +++ b/go/ql/lib/semmle/go/controlflow/BasicBlocks.qll @@ -4,140 +4,62 @@ import go private import ControlFlowGraphImpl +private import codeql.controlflow.BasicBlock as BB +private import codeql.controlflow.SuccessorType -/** - * Holds if `nd` starts a new basic block. - */ -private predicate startsBB(ControlFlow::Node nd) { - count(nd.getAPredecessor()) != 1 - or - nd.getAPredecessor().isBranch() -} +private module Input implements BB::InputSig { + /** A delineated part of the AST with its own CFG. */ + class CfgScope = ControlFlow::Root; -/** - * Holds if the first node of basic block `succ` is a control flow - * successor of the last node of basic block `bb`. - */ -private predicate succBB(BasicBlock bb, BasicBlock succ) { succ = bb.getLastNode().getASuccessor() } + /** The class of control flow nodes. */ + class Node = ControlFlowNode; -/** - * Holds if the first node of basic block `bb` is a control flow - * successor of the last node of basic block `pre`. - */ -private predicate predBB(BasicBlock bb, BasicBlock pre) { succBB(pre, bb) } + /** Gets the CFG scope in which this node occurs. */ + CfgScope nodeGetCfgScope(Node node) { node.getRoot() = result } -/** Holds if `bb` is an entry basic block. */ -private predicate entryBB(BasicBlock bb) { bb.getFirstNode().isEntryNode() } - -/** Holds if `bb` is an exit basic block. */ -private predicate exitBB(BasicBlock bb) { bb.getLastNode().isExitNode() } - -cached -private module Internal { - /** - * Holds if `succ` is a control flow successor of `nd` within the same basic block. - */ - private predicate intraBBSucc(ControlFlow::Node nd, ControlFlow::Node succ) { - succ = nd.getASuccessor() and - not startsBB(succ) + /** Gets an immediate successor of this node. */ + Node nodeGetASuccessor(Node node, SuccessorType t) { + result = node.getASuccessor() and + ( + not result instanceof ControlFlow::ConditionGuardNode and t instanceof DirectSuccessor + or + t.(BooleanSuccessor).getValue() = result.(ControlFlow::ConditionGuardNode).getOutcome() + ) } /** - * Holds if `nd` is the `i`th node in basic block `bb`. - * - * In other words, `i` is the shortest distance from a node `bb` - * that starts a basic block to `nd` along the `intraBBSucc` relation. + * Holds if `node` represents an entry node to be used when calculating + * dominance. */ - cached - predicate bbIndex(BasicBlock bb, ControlFlow::Node nd, int i) = - shortestDistances(startsBB/1, intraBBSucc/2)(bb, nd, i) + predicate nodeIsDominanceEntry(Node node) { node instanceof EntryNode } - cached - int bbLength(BasicBlock bb) { result = strictcount(ControlFlow::Node nd | bbIndex(bb, nd, _)) } - - cached - predicate reachableBB(BasicBlock bb) { - entryBB(bb) - or - exists(BasicBlock predBB | succBB(predBB, bb) | reachableBB(predBB)) - } + /** + * Holds if `node` represents an exit node to be used when calculating + * post dominance. + */ + predicate nodeIsPostDominanceExit(Node node) { node instanceof ExitNode } } -private import Internal - -/** Holds if `dom` is an immediate dominator of `bb`. */ -cached -private predicate bbIDominates(BasicBlock dom, BasicBlock bb) = - idominance(entryBB/1, succBB/2)(_, dom, bb) - -/** Holds if `dom` is an immediate post-dominator of `bb`. */ -cached -private predicate bbIPostDominates(BasicBlock dom, BasicBlock bb) = - idominance(exitBB/1, predBB/2)(_, dom, bb) - -/** - * A basic block, that is, a maximal straight-line sequence of control flow nodes - * without branches or joins. - * - * At the database level, a basic block is represented by its first control flow node. - */ -class BasicBlock extends TControlFlowNode { - BasicBlock() { startsBB(this) } +private module BbImpl = BB::Make; +class BasicBlock extends BbImpl::BasicBlock { /** Gets a basic block succeeding this one. */ - BasicBlock getASuccessor() { succBB(this, result) } + BasicBlock getASuccessor() { result = this.getASuccessor(_) } /** Gets a basic block preceding this one. */ BasicBlock getAPredecessor() { result.getASuccessor() = this } - /** Gets a node in this block. */ - ControlFlow::Node getANode() { result = this.getNode(_) } - - /** Gets the node at the given position in this block. */ - ControlFlow::Node getNode(int pos) { bbIndex(this, result, pos) } - - /** Gets the first node in this block. */ - ControlFlow::Node getFirstNode() { result = this } - - /** Gets the last node in this block. */ - ControlFlow::Node getLastNode() { result = this.getNode(this.length() - 1) } - - /** Gets the length of this block. */ - int length() { result = bbLength(this) } - - /** Gets the basic block that immediately dominates this basic block. */ - ReachableBasicBlock getImmediateDominator() { bbIDominates(result, this) } - /** Gets the innermost function or file to which this basic block belongs. */ - ControlFlow::Root getRoot() { result = this.getFirstNode().getRoot() } - - /** Gets a textual representation of this basic block. */ - string toString() { result = "basic block" } - - /** Gets the source location for this element. */ - Location getLocation() { result = this.getFirstNode().getLocation() } - - /** - * DEPRECATED: Use `getLocation()` instead. - * - * Holds if this basic block is at the specified location. - * The location spans column `startcolumn` of line `startline` to - * column `endcolumn` of line `endline` in file `filepath`. - * For more information, see - * [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/). - */ - deprecated predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) - } + ControlFlow::Root getRoot() { result = this.getScope() } } -/** - * An entry basic block, that is, a basic block whose first node is an entry node. - */ -class EntryBasicBlock extends BasicBlock { - EntryBasicBlock() { entryBB(this) } +class EntryBasicBlock = BbImpl::EntryBasicBlock; + +cached +private predicate reachableBB(BasicBlock bb) { + bb instanceof EntryBasicBlock + or + exists(BasicBlock predBB | predBB.getASuccessor() = bb | reachableBB(predBB)) } /** @@ -145,38 +67,6 @@ class EntryBasicBlock extends BasicBlock { */ class ReachableBasicBlock extends BasicBlock { ReachableBasicBlock() { reachableBB(this) } - - /** - * Holds if this basic block strictly dominates `bb`. - */ - cached - predicate strictlyDominates(ReachableBasicBlock bb) { bbIDominates+(this, bb) } - - /** - * Holds if this basic block dominates `bb`. - * - * This predicate is reflexive: each reachable basic block dominates itself. - */ - predicate dominates(ReachableBasicBlock bb) { - bb = this or - this.strictlyDominates(bb) - } - - /** - * Holds if this basic block strictly post-dominates `bb`. - */ - cached - predicate strictlyPostDominates(ReachableBasicBlock bb) { bbIPostDominates+(this, bb) } - - /** - * Holds if this basic block post-dominates `bb`. - * - * This predicate is reflexive: each reachable basic block post-dominates itself. - */ - predicate postDominates(ReachableBasicBlock bb) { - bb = this or - this.strictlyPostDominates(bb) - } } /** @@ -184,21 +74,4 @@ class ReachableBasicBlock extends BasicBlock { */ class ReachableJoinBlock extends ReachableBasicBlock { ReachableJoinBlock() { this.getFirstNode().isJoin() } - - /** - * Holds if this basic block belongs to the dominance frontier of `b`, that is - * `b` dominates a predecessor of this block, but not this block itself. - * - * Algorithm from Cooper et al., "A Simple, Fast Dominance Algorithm" (Figure 5), - * who in turn attribute it to Ferrante et al., "The program dependence graph and - * its use in optimization". - */ - predicate inDominanceFrontierOf(ReachableBasicBlock b) { - b = this.getAPredecessor() and not b = this.getImmediateDominator() - or - exists(ReachableBasicBlock prev | this.inDominanceFrontierOf(prev) | - b = prev.getImmediateDominator() and - not b = this.getImmediateDominator() - ) - } } diff --git a/go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll b/go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll index 355f98a705b..88adb88c026 100644 --- a/go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll +++ b/go/ql/lib/semmle/go/controlflow/ControlFlowGraph.qll @@ -353,4 +353,6 @@ module ControlFlow { } } +class ControlFlowNode = ControlFlow::Node; + class Write = ControlFlow::WriteNode; diff --git a/go/ql/lib/semmle/go/dataflow/SsaImpl.qll b/go/ql/lib/semmle/go/dataflow/SsaImpl.qll index 8549d9b497a..9689c998acf 100644 --- a/go/ql/lib/semmle/go/dataflow/SsaImpl.qll +++ b/go/ql/lib/semmle/go/dataflow/SsaImpl.qll @@ -71,7 +71,7 @@ private module Internal { private predicate inDefDominanceFrontier(ReachableJoinBlock bb, SsaSourceVariable v) { exists(ReachableBasicBlock defbb, SsaDefinition def | def.definesAt(defbb, _, v) and - bb.inDominanceFrontierOf(defbb) + defbb.inDominanceFrontier(bb) ) }