Merge pull request #19505 from aschackmull/java/basicblock

Java: Use the shared BasicBlocks library.
This commit is contained in:
Anders Schack-Mulligen
2025-05-21 13:37:19 +02:00
committed by GitHub
39 changed files with 332 additions and 234 deletions

View File

@@ -10,7 +10,7 @@ private import SemanticExprSpecific::SemanticExprConfig as Specific
*/
class SemBasicBlock extends Specific::BasicBlock {
/** Holds if this block (transitively) dominates `otherblock`. */
final predicate bbDominates(SemBasicBlock otherBlock) { Specific::bbDominates(this, otherBlock) }
final predicate dominates(SemBasicBlock otherBlock) { Specific::bbDominates(this, otherBlock) }
/** Gets an expression that is evaluated in this basic block. */
final SemExpr getAnExpr() { result.getBasicBlock() = this }

View File

@@ -0,0 +1,4 @@
---
category: deprecated
---
* Java now uses the shared `BasicBlock` library. This means that the names of several member predicates have been changed to align with the names used in other languages. The old predicates have been deprecated. The `BasicBlock` class itself no longer extends `ControlFlowNode` - the predicate `getFirstNode` can be used to fix any QL code that somehow relied on this.

View File

@@ -6,6 +6,7 @@ extractor: java
library: true
upgrades: upgrades
dependencies:
codeql/controlflow: ${workspace}
codeql/dataflow: ${workspace}
codeql/mad: ${workspace}
codeql/quantum: ${workspace}

View File

@@ -4,91 +4,128 @@
import java
import Dominance
private import codeql.controlflow.BasicBlock as BB
cached
private module BasicBlockStage {
cached
predicate ref() { any() }
private module Input implements BB::InputSig<Location> {
import SuccessorType
cached
predicate backref() {
(exists(any(BasicBlock bb).getABBSuccessor()) implies any()) and
(exists(any(BasicBlock bb).getNode(_)) implies any()) and
(exists(any(BasicBlock bb).length()) implies any())
/** Hold if `t` represents a conditional successor type. */
predicate successorTypeIsCondition(SuccessorType t) { none() }
/** A delineated part of the AST with its own CFG. */
class CfgScope = Callable;
/** The class of control flow nodes. */
class Node = ControlFlowNode;
/** Gets the CFG scope in which this node occurs. */
CfgScope nodeGetCfgScope(Node node) { node.getEnclosingCallable() = result }
private Node getASpecificSuccessor(Node node, SuccessorType t) {
node.(ConditionNode).getABranchSuccessor(t.(BooleanSuccessor).getValue()) = result
or
node.getAnExceptionSuccessor() = result and t instanceof ExceptionSuccessor
}
/** Gets an immediate successor of this node. */
Node nodeGetASuccessor(Node node, SuccessorType t) {
result = getASpecificSuccessor(node, t)
or
node.getASuccessor() = result and
t instanceof NormalSuccessor and
not result = getASpecificSuccessor(node, _)
}
/**
* Holds if `node` represents an entry node to be used when calculating
* dominance.
*/
predicate nodeIsDominanceEntry(Node node) {
exists(Stmt entrystmt | entrystmt = node.asStmt() |
exists(Callable c | entrystmt = c.getBody())
or
// This disjunct is technically superfluous, but safeguards against extractor problems.
entrystmt instanceof BlockStmt and
not exists(entrystmt.getEnclosingCallable()) and
not entrystmt.getParent() instanceof Stmt
)
}
/**
* Holds if `node` represents an exit node to be used when calculating
* post dominance.
*/
predicate nodeIsPostDominanceExit(Node node) { node instanceof ControlFlow::ExitNode }
}
private module BbImpl = BB::Make<Location, Input>;
import BbImpl
/** Holds if the dominance relation is calculated for `bb`. */
predicate hasDominanceInformation(BasicBlock bb) {
exists(BasicBlock entry |
Input::nodeIsDominanceEntry(entry.getFirstNode()) and entry.getASuccessor*() = bb
)
}
/**
* A control-flow node that represents the start of a basic block.
*
* A basic block is a series of nodes with no control-flow branching, which can
* often be treated as a unit in analyses.
* A basic block, that is, a maximal straight-line sequence of control flow nodes
* without branches or joins.
*/
class BasicBlock extends ControlFlowNode {
cached
BasicBlock() {
BasicBlockStage::ref() and
not exists(this.getAPredecessor()) and
exists(this.getASuccessor())
or
strictcount(this.getAPredecessor()) > 1
or
exists(ControlFlowNode pred | pred = this.getAPredecessor() |
strictcount(pred.getASuccessor()) > 1
)
}
class BasicBlock extends BbImpl::BasicBlock {
/** Gets the immediately enclosing callable whose body contains this node. */
Callable getEnclosingCallable() { result = this.getScope() }
/** Gets an immediate successor of this basic block. */
cached
BasicBlock getABBSuccessor() {
BasicBlockStage::ref() and
result = this.getLastNode().getASuccessor()
}
/**
* 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) { super.dominates(bb) }
/** Gets an immediate predecessor of this basic block. */
BasicBlock getABBPredecessor() { result.getABBSuccessor() = this }
/**
* DEPRECATED: Use `getASuccessor` instead.
*
* Gets an immediate successor of this basic block.
*/
deprecated BasicBlock getABBSuccessor() { result = this.getASuccessor() }
/** Gets a control-flow node contained in this basic block. */
ControlFlowNode getANode() { result = this.getNode(_) }
/**
* DEPRECATED: Use `getAPredecessor` instead.
*
* Gets an immediate predecessor of this basic block.
*/
deprecated BasicBlock getABBPredecessor() { result.getASuccessor() = this }
/** Gets the control-flow node at a specific (zero-indexed) position in this basic block. */
cached
ControlFlowNode getNode(int pos) {
BasicBlockStage::ref() and
result = this and
pos = 0
or
exists(ControlFlowNode mid, int mid_pos | pos = mid_pos + 1 |
this.getNode(mid_pos) = mid and
mid.getASuccessor() = result and
not result instanceof BasicBlock
)
}
/**
* DEPRECATED: Use `strictlyDominates` instead.
*
* Holds if this basic block strictly dominates `node`.
*/
deprecated predicate bbStrictlyDominates(BasicBlock node) { this.strictlyDominates(node) }
/** Gets the first control-flow node in this basic block. */
ControlFlowNode getFirstNode() { result = this }
/**
* DEPRECATED: Use `dominates` instead.
*
* Holds if this basic block dominates `node`. (This is reflexive.)
*/
deprecated predicate bbDominates(BasicBlock node) { this.dominates(node) }
/** Gets the last control-flow node in this basic block. */
ControlFlowNode getLastNode() { result = this.getNode(this.length() - 1) }
/**
* DEPRECATED: Use `strictlyPostDominates` instead.
*
* Holds if this basic block strictly post-dominates `node`.
*/
deprecated predicate bbStrictlyPostDominates(BasicBlock node) { this.strictlyPostDominates(node) }
/** Gets the number of control-flow nodes contained in this basic block. */
cached
int length() {
BasicBlockStage::ref() and
result = strictcount(this.getANode())
}
/** Holds if this basic block strictly dominates `node`. */
predicate bbStrictlyDominates(BasicBlock node) { bbStrictlyDominates(this, node) }
/** Holds if this basic block dominates `node`. (This is reflexive.) */
predicate bbDominates(BasicBlock node) { bbDominates(this, node) }
/** Holds if this basic block strictly post-dominates `node`. */
predicate bbStrictlyPostDominates(BasicBlock node) { bbStrictlyPostDominates(this, node) }
/** Holds if this basic block post-dominates `node`. (This is reflexive.) */
predicate bbPostDominates(BasicBlock node) { bbPostDominates(this, node) }
/**
* DEPRECATED: Use `postDominates` instead.
*
* Holds if this basic block post-dominates `node`. (This is reflexive.)
*/
deprecated predicate bbPostDominates(BasicBlock node) { this.postDominates(node) }
}
/** A basic block that ends in an exit node. */

View File

@@ -8,91 +8,75 @@ import java
* Predicates for basic-block-level dominance.
*/
/** Entry points for control-flow. */
private predicate flowEntry(BasicBlock entry) {
exists(Stmt entrystmt | entrystmt = entry.getFirstNode().asStmt() |
exists(Callable c | entrystmt = c.getBody())
or
// This disjunct is technically superfluous, but safeguards against extractor problems.
entrystmt instanceof BlockStmt and
not exists(entry.getEnclosingCallable()) and
not entrystmt.getParent() instanceof Stmt
)
}
/** The successor relation for basic blocks. */
private predicate bbSucc(BasicBlock pre, BasicBlock post) { post = pre.getABBSuccessor() }
/** The immediate dominance relation for basic blocks. */
cached
predicate bbIDominates(BasicBlock dom, BasicBlock node) =
idominance(flowEntry/1, bbSucc/2)(_, dom, node)
/** Holds if the dominance relation is calculated for `bb`. */
predicate hasDominanceInformation(BasicBlock bb) {
exists(BasicBlock entry | flowEntry(entry) and bbSucc*(entry, bb))
/**
* DEPRECATED: Use `BasicBlock::immediatelyDominates` instead.
*
* The immediate dominance relation for basic blocks.
*/
deprecated predicate bbIDominates(BasicBlock dom, BasicBlock node) {
dom.immediatelyDominates(node)
}
/** Exit points for basic-block control-flow. */
private predicate bbSink(BasicBlock exit) { exit.getLastNode() instanceof ControlFlow::ExitNode }
/** Reversed `bbSucc`. */
private predicate bbPred(BasicBlock post, BasicBlock pre) { post = pre.getABBSuccessor() }
private predicate bbPred(BasicBlock post, BasicBlock pre) { post = pre.getASuccessor() }
/** The immediate post-dominance relation on basic blocks. */
cached
predicate bbIPostDominates(BasicBlock dominator, BasicBlock node) =
deprecated predicate bbIPostDominates(BasicBlock dominator, BasicBlock node) =
idominance(bbSink/1, bbPred/2)(_, dominator, node)
/** Holds if `dom` strictly dominates `node`. */
predicate bbStrictlyDominates(BasicBlock dom, BasicBlock node) { bbIDominates+(dom, node) }
/** Holds if `dom` dominates `node`. (This is reflexive.) */
predicate bbDominates(BasicBlock dom, BasicBlock node) {
bbStrictlyDominates(dom, node) or dom = node
/**
* DEPRECATED: Use `BasicBlock::strictlyDominates` instead.
*
* Holds if `dom` strictly dominates `node`.
*/
deprecated predicate bbStrictlyDominates(BasicBlock dom, BasicBlock node) {
dom.strictlyDominates(node)
}
/** Holds if `dom` strictly post-dominates `node`. */
predicate bbStrictlyPostDominates(BasicBlock dom, BasicBlock node) { bbIPostDominates+(dom, node) }
/**
* DEPRECATED: Use `BasicBlock::dominates` instead.
*
* Holds if `dom` dominates `node`. (This is reflexive.)
*/
deprecated predicate bbDominates(BasicBlock dom, BasicBlock node) { dom.dominates(node) }
/** Holds if `dom` post-dominates `node`. (This is reflexive.) */
predicate bbPostDominates(BasicBlock dom, BasicBlock node) {
bbStrictlyPostDominates(dom, node) or dom = node
/**
* DEPRECATED: Use `BasicBlock::strictlyPostDominates` instead.
*
* Holds if `dom` strictly post-dominates `node`.
*/
deprecated predicate bbStrictlyPostDominates(BasicBlock dom, BasicBlock node) {
dom.strictlyPostDominates(node)
}
/**
* DEPRECATED: Use `BasicBlock::postDominates` instead.
*
* Holds if `dom` post-dominates `node`. (This is reflexive.)
*/
deprecated predicate bbPostDominates(BasicBlock dom, BasicBlock node) { dom.postDominates(node) }
/**
* The dominance frontier relation for basic blocks.
*
* This is equivalent to:
*
* ```
* bbDominates(x, w.getABBPredecessor()) and not bbStrictlyDominates(x, w)
* x.dominates(w.getAPredecessor()) and not x.strictlyDominates(w)
* ```
*/
predicate dominanceFrontier(BasicBlock x, BasicBlock w) {
x = w.getABBPredecessor() and not bbIDominates(x, w)
x = w.getAPredecessor() and not x.immediatelyDominates(w)
or
exists(BasicBlock prev | dominanceFrontier(prev, w) |
bbIDominates(x, prev) and
not bbIDominates(x, w)
x.immediatelyDominates(prev) and
not x.immediatelyDominates(w)
)
}
/**
* Holds if `(bb1, bb2)` is an edge that dominates `bb2`, that is, all other
* predecessors of `bb2` are dominated by `bb2`. This implies that `bb1` is the
* immediate dominator of `bb2`.
*
* This is a necessary and sufficient condition for an edge to dominate anything,
* and in particular `dominatingEdge(bb1, bb2) and bb2.bbDominates(bb3)` means
* that the edge `(bb1, bb2)` dominates `bb3`.
*/
predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) {
bbIDominates(bb1, bb2) and
bb1.getABBSuccessor() = bb2 and
forall(BasicBlock pred | pred = bb2.getABBPredecessor() and pred != bb1 | bbDominates(bb2, pred))
}
/*
* Predicates for expression-level dominance.
*/
@@ -102,7 +86,7 @@ predicate iDominates(ControlFlowNode dominator, ControlFlowNode node) {
exists(BasicBlock bb, int i | dominator = bb.getNode(i) and node = bb.getNode(i + 1))
or
exists(BasicBlock dom, BasicBlock bb |
bbIDominates(dom, bb) and
dom.immediatelyDominates(bb) and
dominator = dom.getLastNode() and
node = bb.getFirstNode()
)
@@ -112,7 +96,7 @@ predicate iDominates(ControlFlowNode dominator, ControlFlowNode node) {
pragma[inline]
predicate strictlyDominates(ControlFlowNode dom, ControlFlowNode node) {
// This predicate is gigantic, so it must be inlined.
bbStrictlyDominates(dom.getBasicBlock(), node.getBasicBlock())
dom.getBasicBlock().strictlyDominates(node.getBasicBlock())
or
exists(BasicBlock b, int i, int j | dom = b.getNode(i) and node = b.getNode(j) and i < j)
}
@@ -121,7 +105,7 @@ predicate strictlyDominates(ControlFlowNode dom, ControlFlowNode node) {
pragma[inline]
predicate dominates(ControlFlowNode dom, ControlFlowNode node) {
// This predicate is gigantic, so it must be inlined.
bbStrictlyDominates(dom.getBasicBlock(), node.getBasicBlock())
dom.getBasicBlock().strictlyDominates(node.getBasicBlock())
or
exists(BasicBlock b, int i, int j | dom = b.getNode(i) and node = b.getNode(j) and i <= j)
}
@@ -130,7 +114,7 @@ predicate dominates(ControlFlowNode dom, ControlFlowNode node) {
pragma[inline]
predicate strictlyPostDominates(ControlFlowNode dom, ControlFlowNode node) {
// This predicate is gigantic, so it must be inlined.
bbStrictlyPostDominates(dom.getBasicBlock(), node.getBasicBlock())
dom.getBasicBlock().strictlyPostDominates(node.getBasicBlock())
or
exists(BasicBlock b, int i, int j | dom = b.getNode(i) and node = b.getNode(j) and i > j)
}
@@ -139,7 +123,7 @@ predicate strictlyPostDominates(ControlFlowNode dom, ControlFlowNode node) {
pragma[inline]
predicate postDominates(ControlFlowNode dom, ControlFlowNode node) {
// This predicate is gigantic, so it must be inlined.
bbStrictlyPostDominates(dom.getBasicBlock(), node.getBasicBlock())
dom.getBasicBlock().strictlyPostDominates(node.getBasicBlock())
or
exists(BasicBlock b, int i, int j | dom = b.getNode(i) and node = b.getNode(j) and i >= j)
}

View File

@@ -23,7 +23,7 @@ class ConditionBlock extends BasicBlock {
/** Gets a `true`- or `false`-successor of the last node of this basic block. */
BasicBlock getTestSuccessor(boolean testIsTrue) {
result = this.getConditionNode().getABranchSuccessor(testIsTrue)
result.getFirstNode() = this.getConditionNode().getABranchSuccessor(testIsTrue)
}
/*
@@ -68,7 +68,7 @@ class ConditionBlock extends BasicBlock {
exists(BasicBlock succ |
succ = this.getTestSuccessor(testIsTrue) and
dominatingEdge(this, succ) and
succ.bbDominates(controlled)
succ.dominates(controlled)
)
}
}
@@ -287,7 +287,7 @@ private predicate switchCaseControls(SwitchCase sc, BasicBlock bb) {
// Pattern cases are handled as condition blocks
not sc instanceof PatternCase and
caseblock.getFirstNode() = sc.getControlFlowNode() and
caseblock.bbDominates(bb) and
caseblock.dominates(bb) and
// Check we can't fall through from a previous block:
forall(ControlFlowNode pred | pred = sc.getControlFlowNode().getAPredecessor() |
isNonFallThroughPredecessor(sc, pred)
@@ -300,14 +300,14 @@ private predicate preconditionBranchEdge(
) {
conditionCheckArgument(ma, _, branch) and
bb1.getLastNode() = ma.getControlFlowNode() and
bb2 = bb1.getLastNode().getANormalSuccessor()
bb2.getFirstNode() = bb1.getLastNode().getANormalSuccessor()
}
private predicate preconditionControls(MethodCall ma, BasicBlock controlled, boolean branch) {
exists(BasicBlock check, BasicBlock succ |
preconditionBranchEdge(ma, check, succ, branch) and
dominatingEdge(check, succ) and
succ.bbDominates(controlled)
succ.dominates(controlled)
)
}

View File

@@ -47,7 +47,7 @@ private predicate callAlwaysPerformsAction(Call call, ActionConfiguration conf)
private predicate actionDominatesExit(Callable callable, ActionConfiguration conf) {
exists(ExitBlock exit |
exit.getEnclosingCallable() = callable and
actionBlock(conf).bbDominates(exit)
actionBlock(conf).dominates(exit)
)
}
@@ -56,12 +56,12 @@ private BasicBlock nonDominatingActionBlock(ActionConfiguration conf) {
exists(ExitBlock exit |
result = actionBlock(conf) and
exit.getEnclosingCallable() = result.getEnclosingCallable() and
not result.bbDominates(exit)
not result.dominates(exit)
)
}
private class JoinBlock extends BasicBlock {
JoinBlock() { 2 <= strictcount(this.getABBPredecessor()) }
JoinBlock() { 2 <= strictcount(this.getAPredecessor()) }
}
/**
@@ -72,8 +72,8 @@ private predicate postActionBlock(BasicBlock bb, ActionConfiguration conf) {
bb = nonDominatingActionBlock(conf)
or
if bb instanceof JoinBlock
then forall(BasicBlock pred | pred = bb.getABBPredecessor() | postActionBlock(pred, conf))
else postActionBlock(bb.getABBPredecessor(), conf)
then forall(BasicBlock pred | pred = bb.getAPredecessor() | postActionBlock(pred, conf))
else postActionBlock(bb.getAPredecessor(), conf)
}
/** Holds if every path through `callable` goes through at least one action node. */

View File

@@ -0,0 +1,72 @@
/**
* Provides different types of control flow successor types.
*/
import java
private import codeql.util.Boolean
private newtype TSuccessorType =
TNormalSuccessor() or
TBooleanSuccessor(Boolean branch) or
TExceptionSuccessor()
/** The type of a control flow successor. */
class SuccessorType extends TSuccessorType {
/** Gets a textual representation of successor type. */
string toString() { result = "SuccessorType" }
}
/** A normal control flow successor. */
class NormalSuccessor extends SuccessorType, TNormalSuccessor { }
/**
* An exceptional control flow successor.
*
* This marks control flow edges that are taken when an exception is thrown.
*/
class ExceptionSuccessor extends SuccessorType, TExceptionSuccessor { }
/**
* A conditional control flow successor.
*
* This currently only includes boolean successors (`BooleanSuccessor`).
*/
class ConditionalSuccessor extends SuccessorType, TBooleanSuccessor {
/** Gets the Boolean value of this successor. */
boolean getValue() { this = TBooleanSuccessor(result) }
}
/**
* A Boolean control flow successor.
*
* For example, this program fragment:
*
* ```java
* if (x < 0)
* return 0;
* else
* return 1;
* ```
*
* has a control flow graph containing Boolean successors:
*
* ```
* if
* |
* x < 0
* / \
* / \
* / \
* true false
* | \
* return 0 return 1
* ```
*/
class BooleanSuccessor = ConditionalSuccessor;
/**
* A nullness control flow successor. This is currently unused for Java.
*/
class NullnessSuccessor extends ConditionalSuccessor {
NullnessSuccessor() { none() }
}

View File

@@ -209,7 +209,7 @@ class UnreachableBasicBlock extends BasicBlock {
or
// This block is not reachable in the CFG, and is not the entrypoint in a callable, an
// expression in an assert statement, or a catch clause.
forall(BasicBlock bb | bb = this.getABBPredecessor() | bb instanceof UnreachableBasicBlock) and
forall(BasicBlock bb | bb = this.getAPredecessor() | bb instanceof UnreachableBasicBlock) and
not exists(Callable c | c.getBody().getControlFlowNode() = this.getFirstNode()) and
not this.getFirstNode().asExpr().getEnclosingStmt() instanceof AssertStmt and
not this.getFirstNode().asStmt() instanceof CatchClause
@@ -219,11 +219,10 @@ class UnreachableBasicBlock extends BasicBlock {
// Not accessible from the switch expression
unreachableCaseBlock = constSwitchStmt.getAFailingCase().getBasicBlock() and
// Not accessible from the successful case
not constSwitchStmt.getMatchingCase().getBasicBlock().getABBSuccessor*() =
unreachableCaseBlock
not constSwitchStmt.getMatchingCase().getBasicBlock().getASuccessor*() = unreachableCaseBlock
|
// Blocks dominated by an unreachable case block are unreachable
unreachableCaseBlock.bbDominates(this)
unreachableCaseBlock.dominates(this)
)
}
}

View File

@@ -239,7 +239,7 @@ SsaVariable getADefinition(SsaVariable v, boolean fromBackEdge) {
exists(SsaVariable inp, BasicBlock bb, boolean fbe |
v.(SsaPhiNode).hasInputFromBlock(inp, bb) and
result = getADefinition(inp, fbe) and
(if v.getBasicBlock().bbDominates(bb) then fromBackEdge = true else fromBackEdge = fbe)
(if v.getBasicBlock().dominates(bb) then fromBackEdge = true else fromBackEdge = fbe)
)
}
@@ -290,10 +290,10 @@ private predicate guardImpliesEqual(Guard guard, boolean branch, SsaVariable v,
)
}
private ControlFlowNode getAGuardBranchSuccessor(Guard g, boolean branch) {
result = g.(Expr).getControlFlowNode().(ConditionNode).getABranchSuccessor(branch)
private BasicBlock getAGuardBranchSuccessor(Guard g, boolean branch) {
result.getFirstNode() = g.(Expr).getControlFlowNode().(ConditionNode).getABranchSuccessor(branch)
or
result = g.(SwitchCase).getControlFlowNode() and branch = true
result.getFirstNode() = g.(SwitchCase).getControlFlowNode() and branch = true
}
/**
@@ -306,7 +306,7 @@ private predicate guardControlsPhiBranch(
guard.directlyControls(upd.getBasicBlock(), branch) and
upd.getDefiningExpr().(VariableAssign).getSource() = e and
upd = phi.getAPhiInput() and
guard.getBasicBlock().bbStrictlyDominates(phi.getBasicBlock())
guard.getBasicBlock().strictlyDominates(phi.getBasicBlock())
}
/**
@@ -331,7 +331,7 @@ private predicate conditionalAssign(SsaVariable v, Guard guard, boolean branch,
forall(SsaVariable other | other != upd and other = phi.getAPhiInput() |
guard.directlyControls(other.getBasicBlock(), branch.booleanNot())
or
other.getBasicBlock().bbDominates(guard.getBasicBlock()) and
other.getBasicBlock().dominates(guard.getBasicBlock()) and
not other.isLiveAtEndOfBlock(getAGuardBranchSuccessor(guard, branch))
)
)

View File

@@ -298,9 +298,9 @@ private predicate impossibleEdge(BasicBlock bb1, BasicBlock bb2) {
private predicate leavingFinally(BasicBlock bb1, BasicBlock bb2, boolean normaledge) {
exists(TryStmt try, BlockStmt finally |
try.getFinally() = finally and
bb1.getABBSuccessor() = bb2 and
bb1.getEnclosingStmt().getEnclosingStmt*() = finally and
not bb2.getEnclosingStmt().getEnclosingStmt*() = finally and
bb1.getASuccessor() = bb2 and
bb1.getFirstNode().getEnclosingStmt().getEnclosingStmt*() = finally and
not bb2.getFirstNode().getEnclosingStmt().getEnclosingStmt*() = finally and
if bb1.getLastNode().getANormalSuccessor() = bb2.getFirstNode()
then normaledge = true
else normaledge = false
@@ -339,7 +339,7 @@ private predicate nullVarStep(
midssa.isLiveAtEndOfBlock(mid) and
not ensureNotNull(midssa).getBasicBlock() = mid and
not assertFail(mid, _) and
bb = mid.getABBSuccessor() and
bb = mid.getASuccessor() and
not impossibleEdge(mid, bb) and
not exists(boolean branch | nullGuard(midssa, branch, false).hasBranchEdge(mid, bb, branch)) and
not (leavingFinally(mid, bb, true) and midstoredcompletion = true) and

View File

@@ -209,13 +209,13 @@ module Sem implements Semantic<Location> {
class BasicBlock = J::BasicBlock;
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getABBSuccessor() }
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
private predicate id(ExprParent x, ExprParent y) { x = y }
private predicate idOfAst(ExprParent x, int y) = equivalenceRelation(id/2)(x, y)
private predicate idOf(BasicBlock x, int y) { idOfAst(x.getAstNode(), y) }
private predicate idOf(BasicBlock x, int y) { idOfAst(x.getFirstNode().getAstNode(), y) }
int getBlockId1(BasicBlock bb) { idOf(bb, result) }

View File

@@ -321,14 +321,14 @@ private module Input implements TypeFlowInput<Location> {
*/
private predicate instanceofDisjunct(InstanceOfExpr ioe, BasicBlock bb, BaseSsaVariable v) {
ioe.getExpr() = v.getAUse() and
strictcount(bb.getABBPredecessor()) > 1 and
strictcount(bb.getAPredecessor()) > 1 and
exists(ConditionBlock cb | cb.getCondition() = ioe and cb.getTestSuccessor(true) = bb)
}
/** Holds if `bb` is disjunctively guarded by multiple `instanceof` tests on `v`. */
private predicate instanceofDisjunction(BasicBlock bb, BaseSsaVariable v) {
strictcount(InstanceOfExpr ioe | instanceofDisjunct(ioe, bb, v)) =
strictcount(bb.getABBPredecessor())
strictcount(bb.getAPredecessor())
}
/**
@@ -338,7 +338,7 @@ private module Input implements TypeFlowInput<Location> {
predicate instanceofDisjunctionGuarded(TypeFlowNode n, RefType t) {
exists(BasicBlock bb, InstanceOfExpr ioe, BaseSsaVariable v, VarAccess va |
instanceofDisjunction(bb, v) and
bb.bbDominates(va.getBasicBlock()) and
bb.dominates(va.getBasicBlock()) and
va = v.getAUse() and
instanceofDisjunct(ioe, bb, v) and
t = ioe.getSyntacticCheckedType() and

View File

@@ -145,7 +145,7 @@ private module BaseSsaImpl {
/** Holds if `v` has an implicit definition at the entry, `b`, of the callable. */
predicate hasEntryDef(BaseSsaSourceVariable v, BasicBlock b) {
exists(LocalScopeVariable l, Callable c |
v = TLocalVar(c, l) and c.getBody().getControlFlowNode() = b
v = TLocalVar(c, l) and c.getBody().getBasicBlock() = b
|
l instanceof Parameter or
l.getCallable() != c
@@ -157,15 +157,14 @@ private import BaseSsaImpl
private module SsaInput implements SsaImplCommon::InputSig<Location> {
private import java as J
private import semmle.code.java.controlflow.Dominance as Dom
class BasicBlock = J::BasicBlock;
class ControlFlowNode = J::ControlFlowNode;
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { Dom::bbIDominates(result, bb) }
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) }
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getABBSuccessor() }
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
class SourceVariable = BaseSsaSourceVariable;

View File

@@ -83,12 +83,12 @@ private module CaptureInput implements VariableCapture::InputSig<Location> {
class ControlFlowNode = J::ControlFlowNode;
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { bbIDominates(result, bb) }
BasicBlock getABasicBlockSuccessor(BasicBlock bb) {
result = bb.(J::BasicBlock).getABBSuccessor()
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) {
result.(J::BasicBlock).immediatelyDominates(bb)
}
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.(J::BasicBlock).getASuccessor() }
//TODO: support capture of `this` in lambdas
class CapturedVariable instanceof LocalScopeVariable {
CapturedVariable() {

View File

@@ -40,14 +40,14 @@ private module ThisFlow {
private int lastRank(BasicBlock b) { result = max(int rankix | thisRank(_, b, rankix)) }
private predicate blockPrecedesThisAccess(BasicBlock b) { thisAccess(_, b.getABBSuccessor*(), _) }
private predicate blockPrecedesThisAccess(BasicBlock b) { thisAccess(_, b.getASuccessor*(), _) }
private predicate thisAccessBlockReaches(BasicBlock b1, BasicBlock b2) {
thisAccess(_, b1, _) and b2 = b1.getABBSuccessor()
thisAccess(_, b1, _) and b2 = b1.getASuccessor()
or
exists(BasicBlock mid |
thisAccessBlockReaches(b1, mid) and
b2 = mid.getABBSuccessor() and
b2 = mid.getASuccessor() and
not thisAccess(_, mid, _) and
blockPrecedesThisAccess(b2)
)

View File

@@ -144,13 +144,13 @@ private predicate certainVariableUpdate(TrackedVar v, ControlFlowNode n, BasicBl
pragma[nomagic]
private predicate hasEntryDef(TrackedVar v, BasicBlock b) {
exists(LocalScopeVariable l, Callable c |
v = TLocalVar(c, l) and c.getBody().getControlFlowNode() = b
v = TLocalVar(c, l) and c.getBody().getBasicBlock() = b
|
l instanceof Parameter or
l.getCallable() != c
)
or
v instanceof SsaSourceField and v.getEnclosingCallable().getBody().getControlFlowNode() = b
v instanceof SsaSourceField and v.getEnclosingCallable().getBody().getBasicBlock() = b
}
/** Holds if `n` might update the locally tracked variable `v`. */
@@ -165,15 +165,14 @@ private predicate uncertainVariableUpdate(TrackedVar v, ControlFlowNode n, Basic
private module SsaInput implements SsaImplCommon::InputSig<Location> {
private import java as J
private import semmle.code.java.controlflow.Dominance as Dom
class BasicBlock = J::BasicBlock;
class ControlFlowNode = J::ControlFlowNode;
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { Dom::bbIDominates(result, bb) }
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) }
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getABBSuccessor() }
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
class SourceVariable = SsaSourceVariable;

View File

@@ -19,7 +19,7 @@ private predicate id(BB::ExprParent x, BB::ExprParent y) { x = y }
private predicate idOfAst(BB::ExprParent x, int y) = equivalenceRelation(id/2)(x, y)
private predicate idOf(BasicBlock x, int y) { idOfAst(x.getAstNode(), y) }
private predicate idOf(BasicBlock x, int y) { idOfAst(x.getFirstNode().getAstNode(), y) }
private int getId(BasicBlock bb) { idOf(bb, result) }

View File

@@ -24,6 +24,6 @@ private class SslProceedCall extends MethodCall {
/** Holds if `m` trusts all certificates by calling `SslErrorHandler.proceed` unconditionally. */
predicate trustsAllCerts(OnReceivedSslErrorMethod m) {
exists(SslProceedCall pr | pr.getQualifier().(VarAccess).getVariable() = m.handlerArg() |
pr.getBasicBlock().bbPostDominates(m.getBody().getBasicBlock())
pr.getBasicBlock().postDominates(m.getBody().getBasicBlock())
)
}

View File

@@ -21,7 +21,7 @@ private module ValidationMethod<DataFlow::guardChecksSig/3 validationGuard> {
validationMethod(ma.getMethod(), pos) and
ma.getArgument(pos) = rv and
adjacentUseUseSameVar(rv, result.asExpr()) and
ma.getBasicBlock().bbDominates(result.asExpr().getBasicBlock())
ma.getBasicBlock().dominates(result.asExpr().getBasicBlock())
)
}

View File

@@ -168,7 +168,7 @@ private class FullyDecodesUrlBarrier extends DataFlow::Node {
exists(Variable v, Expr e | this.asExpr() = v.getAnAccess() |
fullyDecodesUrlGuard(e) and
e = v.getAnAccess() and
e.getBasicBlock().bbDominates(this.asExpr().getBasicBlock())
e.getBasicBlock().dominates(this.asExpr().getBasicBlock())
)
}
}

View File

@@ -40,16 +40,16 @@ private predicate validatedAccess(VarAccess va) {
guardcall.getControlFlowNode() = node
|
exists(BasicBlock succ |
succ = node.getANormalSuccessor() and
succ.getFirstNode() = node.getANormalSuccessor() and
dominatingEdge(node.getBasicBlock(), succ) and
succ.bbDominates(va.getBasicBlock())
succ.dominates(va.getBasicBlock())
)
or
exists(BasicBlock bb, int i |
bb.getNode(i) = node and
bb.getNode(i + 1) = node.getANormalSuccessor()
|
bb.bbStrictlyDominates(va.getBasicBlock()) or
bb.strictlyDominates(va.getBasicBlock()) or
bb.getNode(any(int j | j > i)).asExpr() = va
)
)

View File

@@ -99,8 +99,8 @@ predicate failedLock(LockType t, BasicBlock lockblock, BasicBlock exblock) {
)
) and
(
lock.getAnExceptionSuccessor() = exblock or
lock.(ConditionNode).getAFalseSuccessor() = exblock
lock.getAnExceptionSuccessor() = exblock.getFirstNode() or
lock.(ConditionNode).getAFalseSuccessor() = exblock.getFirstNode()
)
)
}
@@ -113,7 +113,7 @@ predicate heldByCurrentThreadCheck(LockType t, BasicBlock checkblock, BasicBlock
exists(ConditionBlock conditionBlock |
conditionBlock.getCondition() = t.getIsHeldByCurrentThreadAccess()
|
conditionBlock.getBasicBlock() = checkblock and
conditionBlock = checkblock and
conditionBlock.getTestSuccessor(false) = falsesucc
)
}
@@ -133,7 +133,7 @@ predicate variableLockStateCheck(LockType t, BasicBlock checkblock, BasicBlock f
conditionBlock.getTestSuccessor(true) = t.getUnlockAccess().getBasicBlock() and
conditionBlock.getCondition() = v
|
conditionBlock.getBasicBlock() = checkblock and
conditionBlock = checkblock and
conditionBlock.getTestSuccessor(false) = falsesucc
)
}
@@ -145,9 +145,7 @@ predicate variableLockStateCheck(LockType t, BasicBlock checkblock, BasicBlock f
predicate blockIsLocked(LockType t, BasicBlock src, BasicBlock b, int locks) {
lockUnlockBlock(t, b, locks) and src = b and locks > 0
or
exists(BasicBlock pred, int predlocks, int curlocks, int failedlock |
pred = b.getABBPredecessor()
|
exists(BasicBlock pred, int predlocks, int curlocks, int failedlock | pred = b.getAPredecessor() |
// The number of net locks from the `src` block to the predecessor block `pred` is `predlocks`.
blockIsLocked(t, src, pred, predlocks) and
// The recursive call ensures that at least one lock is held, so do not consider the false

View File

@@ -18,6 +18,6 @@ where
iteration = inner.getAnIterationVariable() and
iteration = outer.getAnIterationVariable() and
inner.getEnclosingStmt+() = outer and
inner.getBasicBlock().getABBSuccessor+() = outer.getCondition().getBasicBlock()
inner.getBasicBlock().getASuccessor+() = outer.getCondition().getBasicBlock()
select inner.getCondition(), "Nested for statement uses loop variable $@ of enclosing $@.",
iteration, iteration.getName(), outer, "for statement"

View File

@@ -37,7 +37,7 @@ predicate overwritten(VariableUpdate upd) {
bb1.getNode(i) = upd.getControlFlowNode() and
bb2.getNode(j) = overwrite.getControlFlowNode()
|
bb1.getABBSuccessor+() = bb2
bb1.getASuccessor+() = bb2
or
bb1 = bb2 and i < j
)

View File

@@ -14,7 +14,7 @@ private predicate blockInSwitch(SwitchStmt s, BasicBlock b) {
private predicate switchCaseControlFlow(SwitchStmt switch, BasicBlock b1, BasicBlock b2) {
blockInSwitch(switch, b1) and
b1.getABBSuccessor() = b2 and
b1.getASuccessor() = b2 and
blockInSwitch(switch, b2)
}

View File

@@ -13,7 +13,7 @@ import semmle.code.java.dataflow.SSA
class SsaConvertibleReadAccess extends VarRead {
SsaConvertibleReadAccess() {
this.getEnclosingCallable().getBody().getBasicBlock().getABBSuccessor*() = this.getBasicBlock() and
this.getEnclosingCallable().getBody().getBasicBlock().getASuccessor*() = this.getBasicBlock() and
(
not exists(this.getQualifier())
or

View File

@@ -1,6 +1,6 @@
import default
import java
import semmle.code.java.controlflow.Dominance
from BasicBlock b, BasicBlock b2
where bbStrictlyDominates(b, b2)
where b.strictlyDominates(b2)
select b, b2

View File

@@ -1,5 +1,5 @@
import default
import java
from BasicBlock b, BasicBlock b2
where b.getABBSuccessor() = b2
where b.getASuccessor() = b2
select b, b2

View File

@@ -16,6 +16,6 @@ predicate dominanceCounterExample(ControlFlowNode entry, ControlFlowNode dom, Co
from Callable c, ControlFlowNode dom, ControlFlowNode node
where
(strictlyDominates(dom, node) or bbStrictlyDominates(dom, node)) and
strictlyDominates(dom, node) and
dominanceCounterExample(c.getBody().getControlFlowNode(), dom, node)
select c, dom, node

View File

@@ -1,6 +1,6 @@
import default
import java
import semmle.code.java.controlflow.Dominance
from BasicBlock b, BasicBlock b2
where bbStrictlyDominates(b, b2)
where b.strictlyDominates(b2)
select b, b2

View File

@@ -1,5 +1,5 @@
import default
import java
from BasicBlock b, BasicBlock b2
where b.getABBSuccessor() = b2
where b.getASuccessor() = b2
select b, b2

View File

@@ -16,6 +16,6 @@ predicate dominanceCounterExample(ControlFlowNode entry, ControlFlowNode dom, Co
from Callable c, ControlFlowNode dom, ControlFlowNode node
where
(strictlyDominates(dom, node) or bbStrictlyDominates(dom, node)) and
strictlyDominates(dom, node) and
dominanceCounterExample(c.getBody().getControlFlowNode(), dom, node)
select c, dom, node

View File

@@ -1,6 +1,6 @@
import default
import java
import semmle.code.java.controlflow.Dominance
from BasicBlock b, BasicBlock b2
where bbStrictlyDominates(b, b2)
where b.strictlyDominates(b2)
select b, b2

View File

@@ -1,5 +1,5 @@
import default
import java
from BasicBlock b, BasicBlock b2
where b.getABBSuccessor() = b2
where b.getASuccessor() = b2
select b, b2

View File

@@ -16,6 +16,6 @@ predicate dominanceCounterExample(ControlFlowNode entry, ControlFlowNode dom, Co
from Callable c, ControlFlowNode dom, ControlFlowNode node
where
(strictlyDominates(dom, node) or bbStrictlyDominates(dom, node)) and
strictlyDominates(dom, node) and
dominanceCounterExample(c.getBody().getControlFlowNode(), dom, node)
select c, dom, node

View File

@@ -51,23 +51,11 @@ signature module InputSig<LocationSig Location> {
module Make<LocationSig Location, InputSig<Location> Input> {
private import Input
final class BasicBlock = BasicBlockImpl;
private Node nodeGetAPredecessor(Node node, SuccessorType s) {
nodeGetASuccessor(result, s) = node
}
/** Holds if this node has more than one predecessor. */
private predicate nodeIsJoin(Node node) { strictcount(nodeGetAPredecessor(node, _)) > 1 }
/** Holds if this node has more than one successor. */
private predicate nodeIsBranch(Node node) { strictcount(nodeGetASuccessor(node, _)) > 1 }
/**
* A basic block, that is, a maximal straight-line sequence of control flow nodes
* without branches or joins.
*/
private class BasicBlockImpl extends TBasicBlockStart {
final class BasicBlock extends TBasicBlockStart {
/** Gets the CFG scope of this basic block. */
CfgScope getScope() { result = nodeGetCfgScope(this.getFirstNode()) }
@@ -78,9 +66,7 @@ module Make<LocationSig Location, InputSig<Location> Input> {
BasicBlock getASuccessor() { result = this.getASuccessor(_) }
/** Gets an immediate successor of this basic block of a given type, if any. */
BasicBlock getASuccessor(SuccessorType t) {
result.getFirstNode() = nodeGetASuccessor(this.getLastNode(), t)
}
BasicBlock getASuccessor(SuccessorType t) { bbSuccessor(this, result, t) }
/** Gets an immediate predecessor of this basic block, if any. */
BasicBlock getAPredecessor() { result.getASuccessor(_) = this }
@@ -259,6 +245,10 @@ module Make<LocationSig Location, InputSig<Location> Input> {
* 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`.
*/
pragma[nomagic]
predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) {
@@ -285,6 +275,16 @@ module Make<LocationSig Location, InputSig<Location> Input> {
cached
private module Cached {
private Node nodeGetAPredecessor(Node node, SuccessorType s) {
nodeGetASuccessor(result, s) = node
}
/** Holds if this node has more than one predecessor. */
private predicate nodeIsJoin(Node node) { strictcount(nodeGetAPredecessor(node, _)) > 1 }
/** Holds if this node has more than one successor. */
private predicate nodeIsBranch(Node node) { strictcount(nodeGetASuccessor(node, _)) > 1 }
/**
* Internal representation of basic blocks. A basic block is represented
* by its first CFG node.
@@ -341,11 +341,19 @@ module Make<LocationSig Location, InputSig<Location> Input> {
cached
Node getNode(BasicBlock bb, int pos) { bbIndex(bb.getFirstNode(), result, pos) }
/** Holds if `bb` is an entry basic block. */
private predicate entryBB(BasicBlock bb) { nodeIsDominanceEntry(bb.getFirstNode()) }
cached
predicate bbSuccessor(BasicBlock bb1, BasicBlock bb2, SuccessorType t) {
bb2.getFirstNode() = nodeGetASuccessor(bb1.getLastNode(), t)
}
/**
* Holds if the first node of basic block `succ` is a control flow
* successor of the last node of basic block `pred`.
*/
private predicate succBB(BasicBlock pred, BasicBlock succ) { pred.getASuccessor(_) = succ }
private predicate succBB(BasicBlock pred, BasicBlock succ) { bbSuccessor(pred, succ, _) }
/** Holds if `dom` is an immediate dominator of `bb`. */
cached
@@ -365,7 +373,4 @@ module Make<LocationSig Location, InputSig<Location> Input> {
}
private import Cached
/** Holds if `bb` is an entry basic block. */
private predicate entryBB(BasicBlock bb) { nodeIsDominanceEntry(bb.getFirstNode()) }
}

View File

@@ -146,7 +146,7 @@ signature module Semantic<LocationSig Location> {
class BasicBlock {
/** Holds if this block (transitively) dominates `otherblock`. */
predicate bbDominates(BasicBlock otherBlock);
predicate dominates(BasicBlock otherBlock);
}
/** Gets an immediate successor of basic block `bb`, if any. */

View File

@@ -205,7 +205,7 @@ module MakeUtils<LocationSig Location, Semantic<Location> Lang, DeltaSig D> {
predicate backEdge(SsaPhiNode phi, SsaVariable inp, SsaReadPositionPhiInputEdge edge) {
edge.phiInput(phi, inp) and
(
phi.getBasicBlock().bbDominates(edge.getOrigBlock()) or
phi.getBasicBlock().dominates(edge.getOrigBlock()) or
irreducibleSccEdge(edge.getOrigBlock(), phi.getBasicBlock())
)
}
@@ -227,7 +227,7 @@ module MakeUtils<LocationSig Location, Semantic<Location> Lang, DeltaSig D> {
private predicate trimmedEdge(BasicBlock pred, BasicBlock succ) {
getABasicBlockSuccessor(pred) = succ and
not succ.bbDominates(pred)
not succ.dominates(pred)
}
/**