Skip to content

Commit f202586

Browse files
committed
Java: Use the shared BasicBlocks library.
1 parent c68579b commit f202586

File tree

14 files changed

+117
-119
lines changed

14 files changed

+117
-119
lines changed

java/ql/lib/qlpack.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ extractor: java
66
library: true
77
upgrades: upgrades
88
dependencies:
9+
codeql/controlflow: ${workspace}
910
codeql/dataflow: ${workspace}
1011
codeql/mad: ${workspace}
1112
codeql/quantum: ${workspace}

java/ql/lib/semmle/code/java/controlflow/BasicBlocks.qll

Lines changed: 68 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,69 @@
44

55
import java
66
import Dominance
7+
private import codeql.controlflow.BasicBlock as BB
78

8-
cached
9-
private module BasicBlockStage {
10-
cached
11-
predicate ref() { any() }
9+
private module Input implements BB::InputSig<Location> {
10+
import SuccessorType
1211

13-
cached
14-
predicate backref() {
15-
(exists(any(BasicBlock bb).getABBSuccessor()) implies any()) and
16-
(exists(any(BasicBlock bb).getNode(_)) implies any()) and
17-
(exists(any(BasicBlock bb).length()) implies any())
12+
/** Hold if `t` represents a conditional successor type. */
13+
predicate successorTypeIsCondition(SuccessorType t) { none() }
14+
15+
/** A delineated part of the AST with its own CFG. */
16+
class CfgScope = Callable;
17+
18+
/** The class of control flow nodes. */
19+
class Node = ControlFlowNode;
20+
21+
/** Gets the CFG scope in which this node occurs. */
22+
CfgScope nodeGetCfgScope(Node node) { node.getEnclosingCallable() = result }
23+
24+
private Node getASpecificSuccessor(Node node, SuccessorType t) {
25+
node.(ConditionNode).getABranchSuccessor(t.(BooleanSuccessor).getValue()) = result
26+
or
27+
node.getAnExceptionSuccessor() = result and t instanceof ExceptionSuccessor
28+
}
29+
30+
/** Gets an immediate successor of this node. */
31+
Node nodeGetASuccessor(Node node, SuccessorType t) {
32+
result = getASpecificSuccessor(node, t)
33+
or
34+
node.getASuccessor() = result and
35+
t instanceof NormalSuccessor and
36+
not result = getASpecificSuccessor(node, _)
1837
}
38+
39+
/**
40+
* Holds if `node` represents an entry node to be used when calculating
41+
* dominance.
42+
*/
43+
predicate nodeIsDominanceEntry(Node node) {
44+
exists(Stmt entrystmt | entrystmt = node.asStmt() |
45+
exists(Callable c | entrystmt = c.getBody())
46+
or
47+
// This disjunct is technically superfluous, but safeguards against extractor problems.
48+
entrystmt instanceof BlockStmt and
49+
not exists(entrystmt.getEnclosingCallable()) and
50+
not entrystmt.getParent() instanceof Stmt
51+
)
52+
}
53+
54+
/**
55+
* Holds if `node` represents an exit node to be used when calculating
56+
* post dominance.
57+
*/
58+
predicate nodeIsPostDominanceExit(Node node) { node instanceof ControlFlow::ExitNode }
59+
}
60+
61+
private module BbImpl = BB::Make<Location, Input>;
62+
63+
import BbImpl
64+
65+
/** Holds if the dominance relation is calculated for `bb`. */
66+
predicate hasDominanceInformation(BasicBlock bb) {
67+
exists(BasicBlock entry |
68+
Input::nodeIsDominanceEntry(entry.getFirstNode()) and entry.getASuccessor*() = bb
69+
)
1970
}
2071

2172
/**
@@ -24,71 +75,27 @@ private module BasicBlockStage {
2475
* A basic block is a series of nodes with no control-flow branching, which can
2576
* often be treated as a unit in analyses.
2677
*/
27-
class BasicBlock extends ControlFlowNode {
28-
cached
29-
BasicBlock() {
30-
BasicBlockStage::ref() and
31-
not exists(this.getAPredecessor()) and
32-
exists(this.getASuccessor())
33-
or
34-
strictcount(this.getAPredecessor()) > 1
35-
or
36-
exists(ControlFlowNode pred | pred = this.getAPredecessor() |
37-
strictcount(pred.getASuccessor()) > 1
38-
)
39-
}
78+
class BasicBlock extends BbImpl::BasicBlock {
79+
/** Gets the immediately enclosing callable whose body contains this node. */
80+
Callable getEnclosingCallable() { result = this.getScope() }
4081

4182
/** Gets an immediate successor of this basic block. */
42-
cached
43-
BasicBlock getABBSuccessor() {
44-
BasicBlockStage::ref() and
45-
result = this.getLastNode().getASuccessor()
46-
}
83+
BasicBlock getABBSuccessor() { result = this.getASuccessor() }
4784

4885
/** Gets an immediate predecessor of this basic block. */
4986
BasicBlock getABBPredecessor() { result.getABBSuccessor() = this }
5087

51-
/** Gets a control-flow node contained in this basic block. */
52-
ControlFlowNode getANode() { result = this.getNode(_) }
53-
54-
/** Gets the control-flow node at a specific (zero-indexed) position in this basic block. */
55-
cached
56-
ControlFlowNode getNode(int pos) {
57-
BasicBlockStage::ref() and
58-
result = this and
59-
pos = 0
60-
or
61-
exists(ControlFlowNode mid, int mid_pos | pos = mid_pos + 1 |
62-
this.getNode(mid_pos) = mid and
63-
mid.getASuccessor() = result and
64-
not result instanceof BasicBlock
65-
)
66-
}
67-
68-
/** Gets the first control-flow node in this basic block. */
69-
ControlFlowNode getFirstNode() { result = this }
70-
71-
/** Gets the last control-flow node in this basic block. */
72-
ControlFlowNode getLastNode() { result = this.getNode(this.length() - 1) }
73-
74-
/** Gets the number of control-flow nodes contained in this basic block. */
75-
cached
76-
int length() {
77-
BasicBlockStage::ref() and
78-
result = strictcount(this.getANode())
79-
}
80-
8188
/** Holds if this basic block strictly dominates `node`. */
82-
predicate bbStrictlyDominates(BasicBlock node) { bbStrictlyDominates(this, node) }
89+
predicate bbStrictlyDominates(BasicBlock node) { this.strictlyDominates(node) }
8390

8491
/** Holds if this basic block dominates `node`. (This is reflexive.) */
85-
predicate bbDominates(BasicBlock node) { bbDominates(this, node) }
92+
predicate bbDominates(BasicBlock node) { this.dominates(node) }
8693

8794
/** Holds if this basic block strictly post-dominates `node`. */
88-
predicate bbStrictlyPostDominates(BasicBlock node) { bbStrictlyPostDominates(this, node) }
95+
predicate bbStrictlyPostDominates(BasicBlock node) { this.strictlyPostDominates(node) }
8996

9097
/** Holds if this basic block post-dominates `node`. (This is reflexive.) */
91-
predicate bbPostDominates(BasicBlock node) { bbPostDominates(this, node) }
98+
predicate bbPostDominates(BasicBlock node) { this.postDominates(node) }
9299
}
93100

94101
/** A basic block that ends in an exit node. */

java/ql/lib/semmle/code/java/controlflow/Dominance.qll

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,8 @@ import java
88
* Predicates for basic-block-level dominance.
99
*/
1010

11-
/** Entry points for control-flow. */
12-
private predicate flowEntry(BasicBlock entry) {
13-
exists(Stmt entrystmt | entrystmt = entry.getFirstNode().asStmt() |
14-
exists(Callable c | entrystmt = c.getBody())
15-
or
16-
// This disjunct is technically superfluous, but safeguards against extractor problems.
17-
entrystmt instanceof BlockStmt and
18-
not exists(entry.getEnclosingCallable()) and
19-
not entrystmt.getParent() instanceof Stmt
20-
)
21-
}
22-
23-
/** The successor relation for basic blocks. */
24-
private predicate bbSucc(BasicBlock pre, BasicBlock post) { post = pre.getABBSuccessor() }
25-
2611
/** The immediate dominance relation for basic blocks. */
27-
cached
28-
predicate bbIDominates(BasicBlock dom, BasicBlock node) =
29-
idominance(flowEntry/1, bbSucc/2)(_, dom, node)
30-
31-
/** Holds if the dominance relation is calculated for `bb`. */
32-
predicate hasDominanceInformation(BasicBlock bb) {
33-
exists(BasicBlock entry | flowEntry(entry) and bbSucc*(entry, bb))
34-
}
12+
predicate bbIDominates(BasicBlock dom, BasicBlock node) { dom.immediatelyDominates(node) }
3513

3614
/** Exit points for basic-block control-flow. */
3715
private predicate bbSink(BasicBlock exit) { exit.getLastNode() instanceof ControlFlow::ExitNode }
@@ -78,21 +56,6 @@ predicate dominanceFrontier(BasicBlock x, BasicBlock w) {
7856
)
7957
}
8058

81-
/**
82-
* Holds if `(bb1, bb2)` is an edge that dominates `bb2`, that is, all other
83-
* predecessors of `bb2` are dominated by `bb2`. This implies that `bb1` is the
84-
* immediate dominator of `bb2`.
85-
*
86-
* This is a necessary and sufficient condition for an edge to dominate anything,
87-
* and in particular `dominatingEdge(bb1, bb2) and bb2.bbDominates(bb3)` means
88-
* that the edge `(bb1, bb2)` dominates `bb3`.
89-
*/
90-
predicate dominatingEdge(BasicBlock bb1, BasicBlock bb2) {
91-
bbIDominates(bb1, bb2) and
92-
bb1.getABBSuccessor() = bb2 and
93-
forall(BasicBlock pred | pred = bb2.getABBPredecessor() and pred != bb1 | bbDominates(bb2, pred))
94-
}
95-
9659
/*
9760
* Predicates for expression-level dominance.
9861
*/

java/ql/lib/semmle/code/java/controlflow/Guards.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class ConditionBlock extends BasicBlock {
2323

2424
/** Gets a `true`- or `false`-successor of the last node of this basic block. */
2525
BasicBlock getTestSuccessor(boolean testIsTrue) {
26-
result = this.getConditionNode().getABranchSuccessor(testIsTrue)
26+
result.getFirstNode() = this.getConditionNode().getABranchSuccessor(testIsTrue)
2727
}
2828

2929
/*
@@ -300,7 +300,7 @@ private predicate preconditionBranchEdge(
300300
) {
301301
conditionCheckArgument(ma, _, branch) and
302302
bb1.getLastNode() = ma.getControlFlowNode() and
303-
bb2 = bb1.getLastNode().getANormalSuccessor()
303+
bb2.getFirstNode() = bb1.getLastNode().getANormalSuccessor()
304304
}
305305

306306
private predicate preconditionControls(MethodCall ma, BasicBlock controlled, boolean branch) {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import java
2+
private import codeql.util.Boolean
3+
4+
private newtype TSuccessorType =
5+
TNormalSuccessor() or
6+
TBooleanSuccessor(Boolean branch) or
7+
TExceptionSuccessor()
8+
9+
class SuccessorType extends TSuccessorType {
10+
string toString() { result = "SuccessorType" }
11+
}
12+
13+
class NormalSuccessor extends SuccessorType, TNormalSuccessor { }
14+
15+
class ExceptionSuccessor extends SuccessorType, TExceptionSuccessor { }
16+
17+
class ConditionalSuccessor extends SuccessorType, TBooleanSuccessor {
18+
boolean getValue() { this = TBooleanSuccessor(result) }
19+
}
20+
21+
class BooleanSuccessor = ConditionalSuccessor;
22+
23+
class NullnessSuccessor extends ConditionalSuccessor {
24+
NullnessSuccessor() { none() }
25+
}

java/ql/lib/semmle/code/java/controlflow/internal/GuardsLogic.qll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -290,10 +290,10 @@ private predicate guardImpliesEqual(Guard guard, boolean branch, SsaVariable v,
290290
)
291291
}
292292

293-
private ControlFlowNode getAGuardBranchSuccessor(Guard g, boolean branch) {
294-
result = g.(Expr).getControlFlowNode().(ConditionNode).getABranchSuccessor(branch)
293+
private BasicBlock getAGuardBranchSuccessor(Guard g, boolean branch) {
294+
result.getFirstNode() = g.(Expr).getControlFlowNode().(ConditionNode).getABranchSuccessor(branch)
295295
or
296-
result = g.(SwitchCase).getControlFlowNode() and branch = true
296+
result.getFirstNode() = g.(SwitchCase).getControlFlowNode() and branch = true
297297
}
298298

299299
/**

java/ql/lib/semmle/code/java/dataflow/Nullness.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -299,8 +299,8 @@ private predicate leavingFinally(BasicBlock bb1, BasicBlock bb2, boolean normale
299299
exists(TryStmt try, BlockStmt finally |
300300
try.getFinally() = finally and
301301
bb1.getABBSuccessor() = bb2 and
302-
bb1.getEnclosingStmt().getEnclosingStmt*() = finally and
303-
not bb2.getEnclosingStmt().getEnclosingStmt*() = finally and
302+
bb1.getFirstNode().getEnclosingStmt().getEnclosingStmt*() = finally and
303+
not bb2.getFirstNode().getEnclosingStmt().getEnclosingStmt*() = finally and
304304
if bb1.getLastNode().getANormalSuccessor() = bb2.getFirstNode()
305305
then normaledge = true
306306
else normaledge = false

java/ql/lib/semmle/code/java/dataflow/RangeAnalysis.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ module Sem implements Semantic<Location> {
215215

216216
private predicate idOfAst(ExprParent x, int y) = equivalenceRelation(id/2)(x, y)
217217

218-
private predicate idOf(BasicBlock x, int y) { idOfAst(x.getAstNode(), y) }
218+
private predicate idOf(BasicBlock x, int y) { idOfAst(x.getFirstNode().getAstNode(), y) }
219219

220220
int getBlockId1(BasicBlock bb) { idOf(bb, result) }
221221

java/ql/lib/semmle/code/java/dataflow/internal/BaseSSA.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ private module BaseSsaImpl {
145145
/** Holds if `v` has an implicit definition at the entry, `b`, of the callable. */
146146
predicate hasEntryDef(BaseSsaSourceVariable v, BasicBlock b) {
147147
exists(LocalScopeVariable l, Callable c |
148-
v = TLocalVar(c, l) and c.getBody().getControlFlowNode() = b
148+
v = TLocalVar(c, l) and c.getBody().getBasicBlock() = b
149149
|
150150
l instanceof Parameter or
151151
l.getCallable() != c

java/ql/lib/semmle/code/java/dataflow/internal/SsaImpl.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,13 +144,13 @@ private predicate certainVariableUpdate(TrackedVar v, ControlFlowNode n, BasicBl
144144
pragma[nomagic]
145145
private predicate hasEntryDef(TrackedVar v, BasicBlock b) {
146146
exists(LocalScopeVariable l, Callable c |
147-
v = TLocalVar(c, l) and c.getBody().getControlFlowNode() = b
147+
v = TLocalVar(c, l) and c.getBody().getBasicBlock() = b
148148
|
149149
l instanceof Parameter or
150150
l.getCallable() != c
151151
)
152152
or
153-
v instanceof SsaSourceField and v.getEnclosingCallable().getBody().getControlFlowNode() = b
153+
v instanceof SsaSourceField and v.getEnclosingCallable().getBody().getBasicBlock() = b
154154
}
155155

156156
/** Holds if `n` might update the locally tracked variable `v`. */

0 commit comments

Comments
 (0)