Skip to content

Commit abf508e

Browse files
committed
Java: Add FieldValueNode to break up cartesian step relation.
1 parent 3a1836c commit abf508e

File tree

6 files changed

+88
-42
lines changed

6 files changed

+88
-42
lines changed

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

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ private import semmle.code.java.dispatch.VirtualDispatch as VirtualDispatch
88
private module DispatchImpl {
99
/** Gets a viable implementation of the target of the given `Call`. */
1010
DataFlowCallable viableCallable(DataFlowCall c) {
11-
result = VirtualDispatch::viableCallable(c.asCall())
11+
result.asCallable() = VirtualDispatch::viableCallable(c.asCall())
1212
or
13-
result.(SummarizedCallable) = c.asCall().getCallee().getSourceDeclaration()
13+
result.(SummarizedCallable).asCallable() = c.asCall().getCallee().getSourceDeclaration()
1414
}
1515

1616
/**
@@ -93,31 +93,32 @@ private module DispatchImpl {
9393
* qualifier is a parameter of the enclosing callable `c`.
9494
*/
9595
predicate mayBenefitFromCallContext(DataFlowCall call, DataFlowCallable c) {
96-
mayBenefitFromCallContext(call.asCall(), c, _)
96+
mayBenefitFromCallContext(call.asCall(), c.asCallable(), _)
9797
}
9898

9999
/**
100100
* Gets a viable dispatch target of `call` in the context `ctx`. This is
101101
* restricted to those `call`s for which a context might make a difference.
102102
*/
103-
Method viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
103+
DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
104104
result = viableCallable(call) and
105105
exists(int i, Callable c, Method def, RefType t, boolean exact, MethodAccess ma |
106106
ma = call.asCall() and
107107
mayBenefitFromCallContext(ma, c, i) and
108-
c = viableCallable(ctx) and
108+
c = viableCallable(ctx).asCallable() and
109109
contextArgHasType(ctx.asCall(), i, t, exact) and
110110
ma.getMethod().getSourceDeclaration() = def
111111
|
112-
exact = true and result = VirtualDispatch::exactMethodImpl(def, t.getSourceDeclaration())
112+
exact = true and
113+
result.asCallable() = VirtualDispatch::exactMethodImpl(def, t.getSourceDeclaration())
113114
or
114115
exact = false and
115116
exists(RefType t2 |
116-
result = VirtualDispatch::viableMethodImpl(def, t.getSourceDeclaration(), t2) and
117+
result.asCallable() = VirtualDispatch::viableMethodImpl(def, t.getSourceDeclaration(), t2) and
117118
not failsUnification(t, t2)
118119
)
119120
or
120-
result = def and def instanceof SummarizedCallable
121+
result.asCallable() = def and result instanceof SummarizedCallable
121122
)
122123
}
123124

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

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ newtype TNode =
1414
not e.getParent*() instanceof Annotation
1515
} or
1616
TExplicitParameterNode(Parameter p) {
17-
exists(p.getCallable().getBody()) or p.getCallable() instanceof SummarizedCallable
17+
exists(p.getCallable().getBody()) or p.getCallable() = any(SummarizedCallable sc).asCallable()
1818
} or
1919
TImplicitVarargsArray(Call c) {
2020
c.getCallee().isVarargs() and
2121
not exists(Argument arg | arg.getCall() = c and arg.isExplicitVarargsArray())
2222
} or
2323
TInstanceParameterNode(Callable c) {
24-
(exists(c.getBody()) or c instanceof SummarizedCallable) and
24+
(exists(c.getBody()) or c = any(SummarizedCallable sc).asCallable()) and
2525
not c.isStatic()
2626
} or
2727
TImplicitInstanceAccess(InstanceAccessExt ia) { not ia.isExplicit(_) } or
@@ -44,7 +44,8 @@ newtype TNode =
4444
} or
4545
TSummaryInternalNode(SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state) {
4646
FlowSummaryImpl::Private::summaryNodeRange(c, state)
47-
}
47+
} or
48+
TFieldValueNode(Field f)
4849

4950
private predicate explicitInstanceArgument(Call call, Expr instarg) {
5051
call instanceof MethodAccess and
@@ -94,19 +95,12 @@ module Public {
9495
result = this.(MallocNode).getClassInstanceExpr().getType()
9596
or
9697
result = this.(ImplicitPostUpdateNode).getPreUpdateNode().getType()
98+
or
99+
result = this.(FieldValueNode).getField().getType()
97100
}
98101

99102
/** Gets the callable in which this node occurs. */
100-
Callable getEnclosingCallable() {
101-
result = this.asExpr().getEnclosingCallable() or
102-
result = this.asParameter().getCallable() or
103-
result = this.(ImplicitVarargsArray).getCall().getEnclosingCallable() or
104-
result = this.(InstanceParameterNode).getCallable() or
105-
result = this.(ImplicitInstanceAccess).getInstanceAccess().getEnclosingCallable() or
106-
result = this.(MallocNode).getClassInstanceExpr().getEnclosingCallable() or
107-
result = this.(ImplicitPostUpdateNode).getPreUpdateNode().getEnclosingCallable() or
108-
this = TSummaryInternalNode(result, _)
109-
}
103+
Callable getEnclosingCallable() { result = nodeGetEnclosingCallable(this).asCallable() }
110104

111105
private Type getImprovedTypeBound() {
112106
exprTypeFlow(this.asExpr(), result, _) or
@@ -257,6 +251,18 @@ module Public {
257251
abstract Node getPreUpdateNode();
258252
}
259253

254+
/**
255+
* A node representing the value of a field.
256+
*/
257+
class FieldValueNode extends Node, TFieldValueNode {
258+
/** Gets the field corresponding to this node. */
259+
Field getField() { this = TFieldValueNode(result) }
260+
261+
override string toString() { result = getField().toString() }
262+
263+
override Location getLocation() { result = getField().getLocation() }
264+
}
265+
260266
/**
261267
* Gets the node that occurs as the qualifier of `fa`.
262268
*/
@@ -305,11 +311,21 @@ private class ImplicitExprPostUpdate extends ImplicitPostUpdateNode, TImplicitEx
305311

306312
module Private {
307313
/** Gets the callable in which this node occurs. */
308-
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
314+
DataFlowCallable nodeGetEnclosingCallable(Node n) {
315+
result.asCallable() = n.asExpr().getEnclosingCallable() or
316+
result.asCallable() = n.asParameter().getCallable() or
317+
result.asCallable() = n.(ImplicitVarargsArray).getCall().getEnclosingCallable() or
318+
result.asCallable() = n.(InstanceParameterNode).getCallable() or
319+
result.asCallable() = n.(ImplicitInstanceAccess).getInstanceAccess().getEnclosingCallable() or
320+
result.asCallable() = n.(MallocNode).getClassInstanceExpr().getEnclosingCallable() or
321+
result = nodeGetEnclosingCallable(n.(ImplicitPostUpdateNode).getPreUpdateNode()) or
322+
n = TSummaryInternalNode(result, _) or
323+
result.asFieldScope() = n.(FieldValueNode).getField()
324+
}
309325

310326
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */
311327
predicate isParameterNode(ParameterNode p, DataFlowCallable c, int pos) {
312-
p.isParameterOf(c, pos)
328+
p.isParameterOf(c.asCallable(), pos)
313329
}
314330

315331
/**

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

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,18 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
3232
/**
3333
* Holds if data can flow from `node1` to `node2` through a static field.
3434
*/
35-
private predicate staticFieldStep(ExprNode node1, ExprNode node2) {
35+
private predicate staticFieldStep(Node node1, Node node2) {
36+
exists(Field f |
37+
f.isStatic() and
38+
f.getAnAssignedValue() = node1.asExpr() and
39+
node2.(FieldValueNode).getField() = f
40+
)
41+
or
3642
exists(Field f, FieldRead fr |
3743
f.isStatic() and
38-
f.getAnAssignedValue() = node1.getExpr() and
44+
node1.(FieldValueNode).getField() = f and
3945
fr.getField() = f and
40-
fr = node2.getExpr() and
46+
fr = node2.asExpr() and
4147
hasNonlocalValue(fr)
4248
)
4349
}
@@ -205,7 +211,30 @@ class CastNode extends ExprNode {
205211
CastNode() { this.getExpr() instanceof CastExpr }
206212
}
207213

208-
class DataFlowCallable = Callable;
214+
private newtype TDataFlowCallable =
215+
TCallable(Callable c) or
216+
TFieldScope(Field f)
217+
218+
class DataFlowCallable extends TDataFlowCallable {
219+
Callable asCallable() { this = TCallable(result) }
220+
221+
Field asFieldScope() { this = TFieldScope(result) }
222+
223+
RefType getDeclaringType() {
224+
result = asCallable().getDeclaringType() or
225+
result = asFieldScope().getDeclaringType()
226+
}
227+
228+
string toString() {
229+
result = asCallable().toString() or
230+
result = "Field scope: " + asFieldScope().toString()
231+
}
232+
233+
Location getLocation() {
234+
result = asCallable().getLocation() or
235+
result = asFieldScope().getLocation()
236+
}
237+
}
209238

210239
class DataFlowExpr = Expr;
211240

@@ -251,7 +280,9 @@ class SrcCall extends DataFlowCall, TCall {
251280

252281
SrcCall() { this = TCall(call) }
253282

254-
override DataFlowCallable getEnclosingCallable() { result = call.getEnclosingCallable() }
283+
override DataFlowCallable getEnclosingCallable() {
284+
result.asCallable() = call.getEnclosingCallable()
285+
}
255286

256287
override string toString() { result = call.toString() }
257288

@@ -345,10 +376,10 @@ class LambdaCallKind = Method; // the "apply" method in the functional interface
345376
predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c) {
346377
exists(ClassInstanceExpr func, Interface t, FunctionalInterface interface |
347378
creation.asExpr() = func and
348-
func.getAnonymousClass().getAMethod() = c and
379+
func.getAnonymousClass().getAMethod() = c.asCallable() and
349380
func.getConstructedType().extendsOrImplements+(t) and
350381
t.getSourceDeclaration() = interface and
351-
c.(Method).overridesOrInstantiates+(pragma[only_bind_into](kind)) and
382+
c.asCallable().(Method).overridesOrInstantiates+(pragma[only_bind_into](kind)) and
352383
pragma[only_bind_into](kind) = interface.getRunMethod().getSourceDeclaration()
353384
)
354385
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ DataFlowType getContentType(Content c) { result = c.getType() }
3030

3131
/** Gets the return type of kind `rk` for callable `c`. */
3232
DataFlowType getReturnType(SummarizedCallable c, ReturnKind rk) {
33-
result = getErasedRepr(c.getReturnType()) and
33+
result = getErasedRepr(c.asCallable().getReturnType()) and
3434
exists(rk)
3535
}
3636

@@ -62,7 +62,7 @@ predicate summaryElement(DataFlowCallable c, string input, string output, string
6262
string namespace, string type, boolean subtypes, string name, string signature, string ext
6363
|
6464
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind) and
65-
c = interpretElement(namespace, type, subtypes, name, signature, ext)
65+
c.asCallable() = interpretElement(namespace, type, subtypes, name, signature, ext)
6666
)
6767
}
6868

@@ -119,7 +119,7 @@ class InterpretNode extends TInterpretNode {
119119
DataFlowCall asCall() { result.asCall() = this.asElement() }
120120

121121
/** Gets the callable that this node corresponds to, if any. */
122-
DataFlowCallable asCallable() { result = this.asElement() }
122+
DataFlowCallable asCallable() { result.asCallable() = this.asElement() }
123123

124124
/** Gets the target of this call, if any. */
125125
Callable getCallTarget() { result = this.asCall().asCall().getCallee().getSourceDeclaration() }

java/ql/lib/semmle/code/java/dispatch/DispatchFlow.qll

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,9 @@ private predicate flowStep(RelevantNode n1, RelevantNode n2) {
189189
n2.(ImplicitInstanceAccess).getInstanceAccess().(OwnInstanceAccess).getEnclosingCallable() = c
190190
)
191191
or
192-
exists(Field f |
193-
f.getAnAssignedValue() = n1.asExpr() and
194-
n2.asExpr().(FieldRead).getField() = f
195-
)
192+
n2.(FieldValueNode).getField().getAnAssignedValue() = n1.asExpr()
193+
or
194+
n2.asExpr().(FieldRead).getField() = n1.(FieldValueNode).getField()
196195
or
197196
exists(EnumType enum, Method getValue |
198197
enum.getAnEnumConstant().getAnAssignedValue() = n1.asExpr() and

java/ql/lib/semmle/code/java/dispatch/ObjFlow.qll

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,9 @@ private predicate step(Node n1, Node n2) {
9494
n2.(ImplicitInstanceAccess).getInstanceAccess().(OwnInstanceAccess).getEnclosingCallable() = c
9595
)
9696
or
97-
exists(Field f |
98-
f.getAnAssignedValue() = n1.asExpr() and
99-
n2.asExpr().(FieldRead).getField() = f
100-
)
97+
n2.(FieldValueNode).getField().getAnAssignedValue() = n1.asExpr()
98+
or
99+
n2.asExpr().(FieldRead).getField() = n1.(FieldValueNode).getField()
101100
or
102101
n2.asExpr().(CastExpr).getExpr() = n1.asExpr()
103102
or
@@ -132,7 +131,7 @@ private predicate step(Node n1, Node n2) {
132131
or
133132
exists(Field v |
134133
containerStep(n1.asExpr(), v.getAnAccess()) and
135-
n2.asExpr() = v.getAnAccess()
134+
n2.(FieldValueNode).getField() = v
136135
)
137136
}
138137

0 commit comments

Comments
 (0)