Skip to content

Commit 4479e03

Browse files
committed
Java: Adopt shared SSA data-flow integration (WIP)
1 parent dfda6e8 commit 4479e03

File tree

20 files changed

+925
-958
lines changed

20 files changed

+925
-958
lines changed

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

Lines changed: 49 additions & 824 deletions
Large diffs are not rendered by default.

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class BaseSsaSourceVariable extends TBaseSsaSourceVariable {
5555
}
5656

5757
cached
58-
private module SsaImpl {
58+
private module BaseSsaImpl {
5959
/** Gets the destination variable of an update of a tracked variable. */
6060
cached
6161
BaseSsaSourceVariable getDestVar(VariableUpdate upd) {
@@ -436,7 +436,7 @@ private module SsaImpl {
436436
}
437437
}
438438

439-
private import SsaImpl
439+
private import BaseSsaImpl
440440
private import SsaDefReaches
441441
import SsaPublic
442442

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

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ private import FlowSummaryImpl as FlowSummaryImpl
1010
private import DataFlowImplCommon as DataFlowImplCommon
1111
private import semmle.code.java.controlflow.Guards
1212
private import semmle.code.java.dataflow.RangeUtils
13+
private import semmle.code.java.dataflow.SSA
14+
private import SsaImpl as SsaImpl
1315

1416
/** Gets a string for approximating the name of a field. */
1517
string approximateFieldContent(FieldContent fc) { result = fc.getField().getName().prefix(1) }
@@ -21,6 +23,30 @@ private predicate deadcode(Expr e) {
2123
)
2224
}
2325

26+
module SsaFlow {
27+
module Impl = SsaImpl::DataFlowIntegration;
28+
29+
Impl::Node asNode(Node n) {
30+
n = TSsaNode(result)
31+
or
32+
result.(Impl::ExprNode).getExpr() = n.asExpr()
33+
or
34+
result.(Impl::ExprPostUpdateNode).getExpr() = n.(PostUpdateNode).getPreUpdateNode().asExpr()
35+
or
36+
TExplicitParameterNode(result.(Impl::ParameterNode).getParameter()) = n
37+
}
38+
39+
predicate localFlowStep(
40+
SsaImpl::Impl::DefinitionExt def, Node nodeFrom, Node nodeTo, boolean isUseStep
41+
) {
42+
Impl::localFlowStep(def, asNode(nodeFrom), asNode(nodeTo), isUseStep)
43+
}
44+
45+
predicate localMustFlowStep(SsaImpl::Impl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
46+
Impl::localMustFlowStep(def, asNode(nodeFrom), asNode(nodeTo))
47+
}
48+
}
49+
2450
cached
2551
private module Cached {
2652
cached
@@ -31,6 +57,7 @@ private module Cached {
3157
not e.getType() instanceof VoidType and
3258
not e.getParent*() instanceof Annotation
3359
} or
60+
TSsaNode(SsaFlow::Impl::SsaNode node) or
3461
TExplicitParameterNode(Parameter p) { exists(p.getCallable().getBody()) } or
3562
TImplicitVarargsArray(Call c) {
3663
c.getCallee().isVarargs() and
@@ -79,6 +106,11 @@ private module Cached {
79106
TMapValueContentApprox() or
80107
TCapturedVariableContentApprox(CapturedVariable v) or
81108
TSyntheticFieldApproxContent()
109+
110+
cached
111+
Node getABarrierNode(Guard guard, SsaVariable def, boolean branch) {
112+
SsaFlow::asNode(result) = SsaImpl::DataFlowIntegration::getABarrierNode(guard, def, branch)
113+
}
82114
}
83115

84116
import Cached
@@ -137,6 +169,8 @@ module Public {
137169
result = this.(FieldValueNode).getField().getType()
138170
or
139171
result instanceof TypeObject and this instanceof AdditionalNode
172+
or
173+
result = this.(SsaNode).getDefinitionExt().getSourceVariable().getType()
140174
}
141175

142176
/** Gets the callable in which this node occurs. */
@@ -358,6 +392,18 @@ module Public {
358392

359393
private import Public
360394

395+
class SsaNode extends Node, TSsaNode {
396+
private SsaFlow::Impl::SsaNode node;
397+
398+
SsaNode() { this = TSsaNode(node) }
399+
400+
SsaImpl::Impl::DefinitionExt getDefinitionExt() { result = node.getDefinitionExt() }
401+
402+
override Location getLocation() { result = node.getLocation() }
403+
404+
override string toString() { result = node.toString() }
405+
}
406+
361407
private class NewExpr extends PostUpdateNode, TExprNode {
362408
NewExpr() { exists(ClassInstanceExpr cie | this = TExprNode(cie)) }
363409

@@ -398,7 +444,8 @@ module Private {
398444
result.asSummarizedCallable() = n.(FlowSummaryNode).getSummarizedCallable() or
399445
result.asCallable() = n.(CaptureNode).getSynthesizedCaptureNode().getEnclosingCallable() or
400446
result.asFieldScope() = n.(FieldValueNode).getField() or
401-
result.asCallable() = any(Expr e | n.(AdditionalNode).nodeAt(e, _)).getEnclosingCallable()
447+
result.asCallable() = any(Expr e | n.(AdditionalNode).nodeAt(e, _)).getEnclosingCallable() or
448+
result.asCallable() = n.(SsaNode).getDefinitionExt().getBasicBlock().getEnclosingCallable()
402449
}
403450

404451
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,11 @@ predicate forceHighPrecision(Content c) {
610610
}
611611

612612
/** Holds if `n` should be hidden from path explanations. */
613-
predicate nodeIsHidden(Node n) { n instanceof FlowSummaryNode }
613+
predicate nodeIsHidden(Node n) {
614+
n instanceof FlowSummaryNode
615+
or
616+
n instanceof SsaNode
617+
}
614618

615619
class LambdaCallKind = Method; // the "apply" method in the functional interface
616620

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

Lines changed: 28 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ private import semmle.code.java.dataflow.FlowSummary
1212
private import semmle.code.java.dataflow.InstanceAccess
1313
private import FlowSummaryImpl as FlowSummaryImpl
1414
private import TaintTrackingUtil as TaintTrackingUtil
15+
private import SsaImpl as SsaImpl
1516
private import DataFlowNodes
1617
import DataFlowNodes::Public
1718

@@ -99,6 +100,10 @@ predicate hasNonlocalValue(FieldRead fr) {
99100
)
100101
}
101102

103+
private predicate capturedVariableRead(Node n) {
104+
n.asExpr().(VarRead).getVariable() instanceof CapturedVariable
105+
}
106+
102107
cached
103108
private module Cached {
104109
/**
@@ -108,7 +113,7 @@ private module Cached {
108113
predicate localFlowStep(Node node1, Node node2) {
109114
simpleLocalFlowStep0(node1, node2, _)
110115
or
111-
adjacentUseUse(node1.asExpr(), node2.asExpr())
116+
SsaFlow::localFlowStep(_, node1, node2, _)
112117
or
113118
// Simple flow through library code is included in the exposed local
114119
// step relation, even though flow is technically inter-procedural
@@ -125,6 +130,19 @@ private module Cached {
125130
predicate simpleLocalFlowStep(Node node1, Node node2, string model) {
126131
simpleLocalFlowStep0(node1, node2, model)
127132
or
133+
exists(boolean isUseStep |
134+
SsaFlow::localFlowStep(_, node1, node2, isUseStep) and
135+
not capturedVariableRead(node2) and
136+
model = ""
137+
|
138+
isUseStep = false
139+
or
140+
not exists(FieldRead fr |
141+
hasNonlocalValue(fr) and fr.getField().isStatic() and fr = node1.asExpr()
142+
) and
143+
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(node1, _)
144+
)
145+
or
128146
any(AdditionalValueStep a).step(node1, node2) and
129147
pragma[only_bind_out](node1.getEnclosingCallable()) =
130148
pragma[only_bind_out](node2.getEnclosingCallable()) and
@@ -147,14 +165,7 @@ predicate localMustFlowStep(Node node1, Node node2) {
147165
node2.(ImplicitInstanceAccess).getInstanceAccess().(OwnInstanceAccess).getEnclosingCallable()
148166
)
149167
or
150-
exists(SsaImplicitInit init |
151-
init.isParameterDefinition(node1.asParameter()) and init.getAUse() = node2.asExpr()
152-
)
153-
or
154-
exists(SsaExplicitUpdate upd |
155-
upd.getDefiningExpr().(VariableAssign).getSource() = node1.asExpr() and
156-
upd.getAUse() = node2.asExpr()
157-
)
168+
SsaFlow::localMustFlowStep(_, node1, node2)
158169
or
159170
node2.asExpr().(CastingExpr).getExpr() = node1.asExpr()
160171
or
@@ -169,10 +180,6 @@ predicate localMustFlowStep(Node node1, Node node2) {
169180

170181
import Cached
171182

172-
private predicate capturedVariableRead(Node n) {
173-
n.asExpr().(VarRead).getVariable() instanceof CapturedVariable
174-
}
175-
176183
/**
177184
* Holds if there is a data flow step from `e1` to `e2` that only steps from
178185
* child to parent in the AST.
@@ -214,34 +221,8 @@ predicate simpleAstFlowStep(Expr e1, Expr e2) {
214221
private predicate simpleLocalFlowStep0(Node node1, Node node2, string model) {
215222
(
216223
TaintTrackingUtil::forceCachingInSameStage() and
217-
// Variable flow steps through adjacent def-use and use-use pairs.
218-
exists(SsaExplicitUpdate upd |
219-
upd.getDefiningExpr().(VariableAssign).getSource() = node1.asExpr() or
220-
upd.getDefiningExpr().(AssignOp) = node1.asExpr() or
221-
upd.getDefiningExpr().(RecordBindingVariableExpr) = node1.asExpr()
222-
|
223-
node2.asExpr() = upd.getAFirstUse() and
224-
not capturedVariableRead(node2)
225-
)
226-
or
227-
exists(SsaImplicitInit init |
228-
init.isParameterDefinition(node1.asParameter()) and
229-
node2.asExpr() = init.getAFirstUse() and
230-
not capturedVariableRead(node2)
231-
)
232-
or
233-
adjacentUseUse(node1.asExpr(), node2.asExpr()) and
234-
not exists(FieldRead fr |
235-
hasNonlocalValue(fr) and fr.getField().isStatic() and fr = node1.asExpr()
236-
) and
237-
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(node1, _) and
238-
not capturedVariableRead(node2)
239-
or
240224
ThisFlow::adjacentThisRefs(node1, node2)
241225
or
242-
adjacentUseUse(node1.(PostUpdateNode).getPreUpdateNode().asExpr(), node2.asExpr()) and
243-
not capturedVariableRead(node2)
244-
or
245226
ThisFlow::adjacentThisRefs(node1.(PostUpdateNode).getPreUpdateNode(), node2)
246227
or
247228
simpleAstFlowStep(node1.asExpr(), node2.asExpr())
@@ -401,13 +382,16 @@ signature predicate guardChecksSig(Guard g, Expr e, boolean branch);
401382
* in data flow and taint tracking.
402383
*/
403384
module BarrierGuard<guardChecksSig/3 guardChecks> {
385+
pragma[nomagic]
386+
private predicate guardChecksSsaDef(Guard g, SsaVariable v, boolean branch) {
387+
guardChecks(g, v.getAUse(), branch)
388+
}
389+
404390
/** Gets a node that is safely guarded by the given guard check. */
405391
Node getABarrierNode() {
406-
exists(Guard g, SsaVariable v, boolean branch, VarRead use |
407-
guardChecks(g, v.getAUse(), branch) and
408-
use = v.getAUse() and
409-
g.controls(use.getBasicBlock(), branch) and
410-
result.asExpr() = use
392+
exists(Guard g, SsaVariable v, boolean branch |
393+
guardChecksSsaDef(g, v, branch) and
394+
result = getABarrierNode(g, v, branch)
411395
)
412396
}
413397
}

0 commit comments

Comments
 (0)