Shared: Use shared SuccessorType in shared Cfg and BasicBlock libs.

This commit is contained in:
Anders Schack-Mulligen
2025-08-28 11:03:45 +02:00
parent 4685b4f8a9
commit 144e34c669
22 changed files with 101 additions and 131 deletions

View File

@@ -101,14 +101,8 @@ private module Implementation implements CfgShared::InputSig<Location> {
last(scope.(CompositeAction), e, c)
}
predicate successorTypeIsSimple(SuccessorType t) { t instanceof DirectSuccessor }
predicate successorTypeIsCondition(SuccessorType t) { t instanceof BooleanSuccessor }
SuccessorType getAMatchingSuccessorType(Completion c) { result = c.getAMatchingSuccessorType() }
predicate isAbnormalExitType(SuccessorType t) { none() }
int idOfAstNode(AstNode node) { none() }
int idOfCfgScope(CfgScope scope) { none() }

View File

@@ -2,6 +2,7 @@
* Provides classes that specify the conditions under which control flows along a given edge.
*/
private import codeql.controlflow.SuccessorType
private import internal.EdgeKindInternal
private newtype TEdgeKind =
@@ -28,6 +29,21 @@ abstract private class EdgeKindImpl extends TEdgeKind {
final class EdgeKind = EdgeKindImpl;
private SuccessorType getAMatchingSpecificSuccessorType(EdgeKind k) {
result.(BooleanSuccessor).getValue() = true and k instanceof TrueEdge
or
result.(BooleanSuccessor).getValue() = false and k instanceof FalseEdge
or
result instanceof ExceptionSuccessor and k instanceof ExceptionEdge
}
SuccessorType getAMatchingSuccessorType(EdgeKind k) {
result = getAMatchingSpecificSuccessorType(k)
or
not exists(getAMatchingSpecificSuccessorType(k)) and
result instanceof DirectSuccessor
}
/**
* A "goto" edge, representing the unconditional successor of an `Instruction`
* or `IRBlock`.

View File

@@ -265,9 +265,9 @@ private predicate isEntryBlock(TIRBlock block) {
}
module IRCfg implements BB::CfgSig<Language::Location> {
class ControlFlowNode = Instruction;
private import codeql.controlflow.SuccessorType
class SuccessorType = EdgeKind;
class ControlFlowNode = Instruction;
final private class FinalIRBlock = IRBlock;
@@ -280,7 +280,12 @@ module IRCfg implements BB::CfgSig<Language::Location> {
BasicBlock getASuccessor() { result = super.getASuccessor() }
BasicBlock getASuccessor(SuccessorType t) { result = super.getSuccessor(t) }
BasicBlock getASuccessor(SuccessorType t) {
exists(EdgeKind k |
result = super.getSuccessor(k) and
t = getAMatchingSuccessorType(k)
)
}
predicate strictlyDominates(BasicBlock bb) { super.strictlyDominates(bb) }

View File

@@ -265,9 +265,9 @@ private predicate isEntryBlock(TIRBlock block) {
}
module IRCfg implements BB::CfgSig<Language::Location> {
class ControlFlowNode = Instruction;
private import codeql.controlflow.SuccessorType
class SuccessorType = EdgeKind;
class ControlFlowNode = Instruction;
final private class FinalIRBlock = IRBlock;
@@ -280,7 +280,12 @@ module IRCfg implements BB::CfgSig<Language::Location> {
BasicBlock getASuccessor() { result = super.getASuccessor() }
BasicBlock getASuccessor(SuccessorType t) { result = super.getSuccessor(t) }
BasicBlock getASuccessor(SuccessorType t) {
exists(EdgeKind k |
result = super.getSuccessor(k) and
t = getAMatchingSuccessorType(k)
)
}
predicate strictlyDominates(BasicBlock bb) { super.strictlyDominates(bb) }

View File

@@ -265,9 +265,9 @@ private predicate isEntryBlock(TIRBlock block) {
}
module IRCfg implements BB::CfgSig<Language::Location> {
class ControlFlowNode = Instruction;
private import codeql.controlflow.SuccessorType
class SuccessorType = EdgeKind;
class ControlFlowNode = Instruction;
final private class FinalIRBlock = IRBlock;
@@ -280,7 +280,12 @@ module IRCfg implements BB::CfgSig<Language::Location> {
BasicBlock getASuccessor() { result = super.getASuccessor() }
BasicBlock getASuccessor(SuccessorType t) { result = super.getSuccessor(t) }
BasicBlock getASuccessor(SuccessorType t) {
exists(EdgeKind k |
result = super.getSuccessor(k) and
t = getAMatchingSuccessorType(k)
)
}
predicate strictlyDominates(BasicBlock bb) { super.strictlyDominates(bb) }

View File

@@ -346,8 +346,6 @@ private class EntryBasicBlockAlias = EntryBasicBlock;
module Cfg implements BB::CfgSig<Location> {
class ControlFlowNode = ControlFlow::Node;
class SuccessorType = ControlFlow::SuccessorType;
class BasicBlock = BasicBlockAlias;
class EntryBasicBlock = EntryBasicBlockAlias;

View File

@@ -79,19 +79,10 @@ private module CfgInput implements CfgShared::InputSig<Location> {
Impl::scopeLast(scope, last, c)
}
class SuccessorType = ST::SuccessorType;
private class SuccessorType = ST::SuccessorType;
SuccessorType getAMatchingSuccessorType(Completion c) { result = c.getAMatchingSuccessorType() }
predicate successorTypeIsSimple(SuccessorType t) { t instanceof ST::DirectSuccessor }
predicate successorTypeIsCondition(SuccessorType t) { t instanceof ST::ConditionalSuccessor }
predicate isAbnormalExitType(SuccessorType t) {
t instanceof ST::ExceptionSuccessor or
t instanceof ST::ExitSuccessor
}
int idOfAstNode(AstNode node) { result = node.getId() }
int idOfCfgScope(CfgScope node) { result = idOfAstNode(node) }

View File

@@ -163,8 +163,6 @@ class ConditionBlock extends PreBasicBlock {
module PreCfg implements BB::CfgSig<Location> {
class ControlFlowNode = ControlFlowElement;
class SuccessorType = Cfg::SuccessorType;
class BasicBlock = PreBasicBlock;
class EntryBasicBlock extends BasicBlock {

View File

@@ -7,10 +7,9 @@ module;
import java
import Dominance
private import codeql.controlflow.BasicBlock as BB
private import codeql.controlflow.SuccessorType
private module Input implements BB::InputSig<Location> {
import codeql.controlflow.SuccessorType
/** Hold if `t` represents a conditional successor type. */
predicate successorTypeIsCondition(SuccessorType t) { none() }
@@ -96,7 +95,7 @@ class BasicBlock extends BbImpl::BasicBlock {
predicate strictlyDominates(BasicBlock bb) { super.strictlyDominates(bb) }
/** 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(SuccessorType t) { result = super.getASuccessor(t) }
BasicBlock getASuccessor() { result = super.getASuccessor() }
@@ -161,8 +160,6 @@ private class BasicBlockAlias = BasicBlock;
module Cfg implements BB::CfgSig<Location> {
class ControlFlowNode = BbImpl::ControlFlowNode;
class SuccessorType = BbImpl::SuccessorType;
class BasicBlock = BasicBlockAlias;
class EntryBasicBlock extends BasicBlock instanceof BbImpl::EntryBasicBlock { }

View File

@@ -139,7 +139,7 @@ private predicate isNonFallThroughPredecessor(SwitchCase sc, ControlFlowNode pre
)
}
private module SuccessorTypes implements SharedGuards::SuccessorTypesSig<SuccessorType> {
private module SuccessorTypes implements SharedGuards::SuccessorTypesSig {
import codeql.controlflow.SuccessorType
}

View File

@@ -372,16 +372,28 @@ module Public {
module Cfg implements BB::CfgSig<Location> {
private import javascript as Js
private import codeql.util.Unit
private import codeql.controlflow.SuccessorType
class ControlFlowNode = Js::ControlFlowNode;
class SuccessorType = Unit;
private predicate conditionSucc(BasicBlock bb1, BasicBlock bb2, boolean branch) {
exists(ConditionGuardNode g |
bb1 = g.getTest().getBasicBlock() and
bb2 = g.getBasicBlock() and
branch = g.getOutcome()
)
}
class BasicBlock extends FinalBasicBlock {
BasicBlock getASuccessor() { result = super.getASuccessor() }
BasicBlock getASuccessor(SuccessorType t) { result = super.getASuccessor() and exists(t) }
BasicBlock getASuccessor(SuccessorType t) {
conditionSucc(this, result, t.(BooleanSuccessor).getValue())
or
result = super.getASuccessor() and
t instanceof DirectSuccessor and
not conditionSucc(this, result, _)
}
predicate strictlyDominates(BasicBlock bb) {
this.(ReachableBasicBlock).strictlyDominates(bb)

View File

@@ -1259,9 +1259,9 @@ private class ControlFlowNodeAlias = ControlFlowNode;
final private class FinalBasicBlock = BasicBlock;
module Cfg implements BB::CfgSig<Location> {
class ControlFlowNode = ControlFlowNodeAlias;
private import codeql.controlflow.SuccessorType
class SuccessorType = Unit;
class ControlFlowNode = ControlFlowNodeAlias;
class BasicBlock extends FinalBasicBlock {
// Note `PY:BasicBlock` does not have a `getLocation`.
@@ -1275,7 +1275,24 @@ module Cfg implements BB::CfgSig<Location> {
BasicBlock getASuccessor() { result = super.getASuccessor() }
BasicBlock getASuccessor(SuccessorType t) { result = super.getASuccessor() and exists(t) }
private BasicBlock getANonDirectSuccessor(SuccessorType t) {
result = this.getATrueSuccessor() and
t.(BooleanSuccessor).getValue() = true
or
result = this.getAFalseSuccessor() and
t.(BooleanSuccessor).getValue() = false
or
result = this.getAnExceptionalSuccessor() and
t instanceof ExceptionSuccessor
}
BasicBlock getASuccessor(SuccessorType t) {
result = this.getANonDirectSuccessor(t)
or
result = super.getASuccessor() and
t instanceof DirectSuccessor and
not result = this.getANonDirectSuccessor(_)
}
predicate strictlyDominates(BasicBlock bb) { super.strictlyDominates(bb) }

View File

@@ -301,13 +301,9 @@ private class BasicBlockAlias = BasicBlock;
private class EntryBasicBlockAlias = EntryBasicBlock;
private class SuccessorTypeAlias = SuccessorType;
module Cfg implements BB::CfgSig<Location> {
class ControlFlowNode = CfgNode;
class SuccessorType = SuccessorTypeAlias;
class BasicBlock = BasicBlockAlias;
class EntryBasicBlock = EntryBasicBlockAlias;

View File

@@ -46,19 +46,10 @@ private module CfgInput implements CfgShared::InputSig<Location> {
scope.(Impl::CfgScopeImpl).exit(last, c)
}
class SuccessorType = Cfg::SuccessorType;
private class SuccessorType = Cfg::SuccessorType;
SuccessorType getAMatchingSuccessorType(Completion c) { result = c.getAMatchingSuccessorType() }
predicate successorTypeIsSimple(SuccessorType t) { t instanceof Cfg::DirectSuccessor }
predicate successorTypeIsCondition(SuccessorType t) { t instanceof Cfg::ConditionalSuccessor }
predicate isAbnormalExitType(SuccessorType t) {
t instanceof Cfg::ExceptionSuccessor or
t instanceof Cfg::ExitSuccessor
}
private predicate id(Ruby::AstNode node1, Ruby::AstNode node2) { node1 = node2 }
private predicate idOf(Ruby::AstNode node, int id) = equivalenceRelation(id/2)(node, id)

View File

@@ -21,8 +21,6 @@ final class JoinPredecessorBasicBlock = BasicBlocksImpl::JoinPredecessorBasicBlo
module Cfg implements BB::CfgSig<Location> {
class ControlFlowNode = ControlFlowGraph::CfgNode;
class SuccessorType = ControlFlowGraph::SuccessorType;
class BasicBlock = BasicBlocksImpl::BasicBlock;
class EntryBasicBlock = BasicBlocksImpl::EntryBasicBlock;

View File

@@ -29,19 +29,11 @@ private module CfgInput implements InputSig<Location> {
Stages::CfgStage::ref()
}
class SuccessorType = Cfg::SuccessorType;
private class SuccessorType = Cfg::SuccessorType;
/** Gets a successor type that matches completion `c`. */
SuccessorType getAMatchingSuccessorType(Completion c) { result = c.getAMatchingSuccessorType() }
/**
* Hold if `c` represents simple (normal) evaluation of a statement or an expression.
*/
predicate successorTypeIsSimple(SuccessorType t) { t instanceof Cfg::DirectSuccessor }
/** Holds if `t` is an abnormal exit type out of a CFG scope. */
predicate isAbnormalExitType(SuccessorType t) { none() }
/** Hold if `t` represents a conditional successor type. */
predicate successorTypeIsCondition(SuccessorType t) { t instanceof Cfg::BooleanSuccessor }

View File

@@ -9,17 +9,12 @@ overlay[local?]
module;
private import codeql.util.Location
private import SuccessorType
/** Provides the language-specific input specification. */
signature module InputSig<LocationSig Location> {
/** 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);
default predicate successorTypeIsCondition(SuccessorType t) { t instanceof ConditionalSuccessor }
/** A delineated part of the AST with its own CFG. */
class CfgScope;
@@ -61,12 +56,6 @@ signature module CfgSig<LocationSig Location> {
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.
@@ -180,8 +169,6 @@ module Make<LocationSig Location, InputSig<Location> Input> implements CfgSig<Lo
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.

View File

@@ -8,6 +8,7 @@ module;
private import codeql.util.Location
private import codeql.util.FileSystem
private import codeql.util.Void
private import SuccessorType
/** Provides the language-specific input specification. */
signature module InputSig<LocationSig Location> {
@@ -59,26 +60,11 @@ signature module InputSig<LocationSig Location> {
/** Holds if `scope` is exited when `last` finishes with completion `c`. */
predicate scopeLast(CfgScope scope, AstNode last, Completion c);
/** A type of a control flow successor. */
class SuccessorType {
/** Gets a textual representation of this successor type. */
string toString();
}
/** Gets a successor type that matches completion `c`. */
SuccessorType getAMatchingSuccessorType(Completion c);
/**
* Hold if `t` represents simple (normal) evaluation of a statement or an
* expression.
*/
predicate successorTypeIsSimple(SuccessorType t);
/** Hold if `t` represents a conditional successor type. */
predicate successorTypeIsCondition(SuccessorType t);
/** Holds if `t` is an abnormal exit type out of a CFG scope. */
predicate isAbnormalExitType(SuccessorType t);
default predicate successorTypeIsCondition(SuccessorType t) { t instanceof ConditionalSuccessor }
/**
* Gets an `id` of `node`. This is used to order the predecessors of a join
@@ -522,7 +508,7 @@ module MakeWithSplitting<
private predicate succEntrySplits(CfgScope pred, AstNode succ, Splits succSplits, SuccessorType t) {
exists(int rnk |
scopeFirst(pred, succ) and
successorTypeIsSimple(t) and
t instanceof DirectSuccessor and
succEntrySplitsFromRank(pred, succ, succSplits, rnk)
|
rnk = 0 and
@@ -1016,7 +1002,7 @@ module MakeWithSplitting<
exists(CfgScope scope |
pred = TAnnotatedExitNode(scope, _) and
result = TExitNode(scope) and
successorTypeIsSimple(t)
t instanceof DirectSuccessor
)
}
@@ -1320,7 +1306,7 @@ module MakeWithSplitting<
label =
strictconcat(SuccessorType t, string s |
succ = getASuccessor(pred, t) and
if successorTypeIsSimple(t) then s = "" else s = t.toString()
if t instanceof DirectSuccessor then s = "" else s = t.toString()
|
s, ", " order by s
)
@@ -1590,8 +1576,6 @@ module MakeWithSplitting<
private class NodeAlias = Node;
private module BasicBlockInputSig implements BB::InputSig<Location> {
class SuccessorType = Input::SuccessorType;
predicate successorTypeIsCondition = Input::successorTypeIsCondition/1;
class CfgScope = CfgScopeAlias;

View File

@@ -51,16 +51,17 @@ overlay[local?]
module;
private import codeql.controlflow.BasicBlock as BB
private import codeql.controlflow.SuccessorType as ST
private import codeql.util.Boolean
private import codeql.util.Location
private import codeql.util.Unit
signature class TypSig;
signature module SuccessorTypesSig<TypSig SuccessorType> {
class ExceptionSuccessor extends SuccessorType;
signature module SuccessorTypesSig {
class ExceptionSuccessor extends ST::SuccessorType;
class ConditionalSuccessor extends SuccessorType {
class ConditionalSuccessor extends ST::SuccessorType {
/** Gets the Boolean value of this successor. */
boolean getValue();
}
@@ -204,8 +205,7 @@ signature module InputSig<LocationSig Location, TypSig ControlFlowNode, TypSig B
/** Provides guards-related predicates and classes. */
module Make<
LocationSig Location, BB::CfgSig<Location> Cfg,
SuccessorTypesSig<Cfg::SuccessorType> SuccessorTypes,
LocationSig Location, BB::CfgSig<Location> Cfg, SuccessorTypesSig SuccessorTypes,
InputSig<Location, Cfg::ControlFlowNode, Cfg::BasicBlock> Input>
{
private module Cfg_ = Cfg;
@@ -320,7 +320,7 @@ module Make<
}
private predicate exceptionBranchPoint(BasicBlock bb1, BasicBlock normalSucc, BasicBlock excSucc) {
exists(SuccessorType norm, ExceptionSuccessor exc |
exists(ST::SuccessorType norm, ExceptionSuccessor exc |
bb1.getASuccessor(norm) = normalSucc and
bb1.getASuccessor(exc) = excSucc and
normalSucc != excSucc and

View File

@@ -339,3 +339,9 @@ class RetrySuccessor extends JumpSuccessor, TRetrySuccessor {
class JavaYieldSuccessor extends JumpSuccessor, TJavaYieldSuccessor {
override string toString() { result = "yield" }
}
/** Holds if `t` is an abnormal exit type out of a CFG scope. */
predicate isAbnormalExitType(SuccessorType t) {
t instanceof ExceptionSuccessor or
t instanceof ExitSuccessor
}

View File

@@ -119,13 +119,9 @@ private class EntryBasicBlockAlias = EntryBasicBlock;
private class ControlFlowNodeAlias = ControlFlowNode;
private class SuccessorTypeAlias = SuccessorType;
module Cfg implements BB::CfgSig<Location> {
class ControlFlowNode = ControlFlowNodeAlias;
class SuccessorType = SuccessorTypeAlias;
class BasicBlock = BasicBlockAlias;
class EntryBasicBlock = EntryBasicBlockAlias;

View File

@@ -48,29 +48,11 @@ module CfgInput implements InputSig<Location> {
CfgScope getCfgScope(AstNode n) { result = scopeOfAst(n.asAstNode()) }
class SuccessorType = Cfg::SuccessorType;
private class SuccessorType = Cfg::SuccessorType;
/** Gets a successor type that matches completion `c`. */
SuccessorType getAMatchingSuccessorType(Completion c) { result = c.getAMatchingSuccessorType() }
/**
* Hold if `c` represents simple (normal) evaluation of a statement or an
* expression.
*/
predicate successorTypeIsSimple(SuccessorType t) { t instanceof Cfg::DirectSuccessor }
/** Holds if `t` is an abnormal exit type out of a CFG scope. */
predicate isAbnormalExitType(SuccessorType t) { t instanceof Cfg::ExceptionSuccessor }
/** Hold if `t` represents a conditional successor type. */
predicate successorTypeIsCondition(SuccessorType t) {
t instanceof Cfg::BooleanSuccessor or
t instanceof Cfg::BreakSuccessor or
t instanceof Cfg::ContinueSuccessor or
t instanceof Cfg::MatchingSuccessor or
t instanceof Cfg::EmptinessSuccessor
}
/** Holds if `first` is first executed when entering `scope`. */
predicate scopeFirst(CfgScope scope, AstNode first) {
scope.(Impl::CfgScope::Range_).entry(first)