Skip to content

Commit 432b0a4

Browse files
authored
Merge pull request github#1766 from aschackmull/java/nested-storestep
Java/C++/C#: Add field flow support for stores in nested fields.
2 parents b33e9f2 + 6ff4fe3 commit 432b0a4

File tree

7 files changed

+109
-32
lines changed

7 files changed

+109
-32
lines changed

cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,12 +215,14 @@ private module ImplCommon {
215215

216216
/*
217217
* Calculation of `predicate store(Node node1, Content f, Node node2)`:
218-
* There are three cases:
218+
* There are four cases:
219219
* - The base case: A direct local assignment given by `storeStep`.
220220
* - A call to a method or constructor with two arguments, `arg1` and `arg2`,
221-
* such the call has the side-effect `arg2.f = arg1`.
221+
* such that the call has the side-effect `arg2.f = arg1`.
222222
* - A call to a method that returns an object in which an argument has been
223223
* stored.
224+
* - A reverse step through a read when the result of the read has been
225+
* stored into. This handles cases like `x.f1.f2 = y`.
224226
* `storeViaSideEffect` covers the first two cases, and `storeReturn` covers
225227
* the third case.
226228
*/
@@ -232,7 +234,8 @@ private module ImplCommon {
232234
cached
233235
predicate store(Node node1, Content f, Node node2) {
234236
storeViaSideEffect(node1, f, node2) or
235-
storeReturn(node1, f, node2)
237+
storeReturn(node1, f, node2) or
238+
read(node2.(PostUpdateNode).getPreUpdateNode(), f, node1.(PostUpdateNode).getPreUpdateNode())
236239
}
237240

238241
private predicate storeViaSideEffect(Node node1, Content f, PostUpdateNode node2) {

cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,12 +215,14 @@ private module ImplCommon {
215215

216216
/*
217217
* Calculation of `predicate store(Node node1, Content f, Node node2)`:
218-
* There are three cases:
218+
* There are four cases:
219219
* - The base case: A direct local assignment given by `storeStep`.
220220
* - A call to a method or constructor with two arguments, `arg1` and `arg2`,
221-
* such the call has the side-effect `arg2.f = arg1`.
221+
* such that the call has the side-effect `arg2.f = arg1`.
222222
* - A call to a method that returns an object in which an argument has been
223223
* stored.
224+
* - A reverse step through a read when the result of the read has been
225+
* stored into. This handles cases like `x.f1.f2 = y`.
224226
* `storeViaSideEffect` covers the first two cases, and `storeReturn` covers
225227
* the third case.
226228
*/
@@ -232,7 +234,8 @@ private module ImplCommon {
232234
cached
233235
predicate store(Node node1, Content f, Node node2) {
234236
storeViaSideEffect(node1, f, node2) or
235-
storeReturn(node1, f, node2)
237+
storeReturn(node1, f, node2) or
238+
read(node2.(PostUpdateNode).getPreUpdateNode(), f, node1.(PostUpdateNode).getPreUpdateNode())
236239
}
237240

238241
private predicate storeViaSideEffect(Node node1, Content f, PostUpdateNode node2) {

csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,12 +215,14 @@ private module ImplCommon {
215215

216216
/*
217217
* Calculation of `predicate store(Node node1, Content f, Node node2)`:
218-
* There are three cases:
218+
* There are four cases:
219219
* - The base case: A direct local assignment given by `storeStep`.
220220
* - A call to a method or constructor with two arguments, `arg1` and `arg2`,
221-
* such the call has the side-effect `arg2.f = arg1`.
221+
* such that the call has the side-effect `arg2.f = arg1`.
222222
* - A call to a method that returns an object in which an argument has been
223223
* stored.
224+
* - A reverse step through a read when the result of the read has been
225+
* stored into. This handles cases like `x.f1.f2 = y`.
224226
* `storeViaSideEffect` covers the first two cases, and `storeReturn` covers
225227
* the third case.
226228
*/
@@ -232,7 +234,8 @@ private module ImplCommon {
232234
cached
233235
predicate store(Node node1, Content f, Node node2) {
234236
storeViaSideEffect(node1, f, node2) or
235-
storeReturn(node1, f, node2)
237+
storeReturn(node1, f, node2) or
238+
read(node2.(PostUpdateNode).getPreUpdateNode(), f, node1.(PostUpdateNode).getPreUpdateNode())
236239
}
237240

238241
private predicate storeViaSideEffect(Node node1, Content f, PostUpdateNode node2) {

java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,12 +215,14 @@ private module ImplCommon {
215215

216216
/*
217217
* Calculation of `predicate store(Node node1, Content f, Node node2)`:
218-
* There are three cases:
218+
* There are four cases:
219219
* - The base case: A direct local assignment given by `storeStep`.
220220
* - A call to a method or constructor with two arguments, `arg1` and `arg2`,
221-
* such the call has the side-effect `arg2.f = arg1`.
221+
* such that the call has the side-effect `arg2.f = arg1`.
222222
* - A call to a method that returns an object in which an argument has been
223223
* stored.
224+
* - A reverse step through a read when the result of the read has been
225+
* stored into. This handles cases like `x.f1.f2 = y`.
224226
* `storeViaSideEffect` covers the first two cases, and `storeReturn` covers
225227
* the third case.
226228
*/
@@ -232,7 +234,8 @@ private module ImplCommon {
232234
cached
233235
predicate store(Node node1, Content f, Node node2) {
234236
storeViaSideEffect(node1, f, node2) or
235-
storeReturn(node1, f, node2)
237+
storeReturn(node1, f, node2) or
238+
read(node2.(PostUpdateNode).getPreUpdateNode(), f, node1.(PostUpdateNode).getPreUpdateNode())
236239
}
237240

238241
private predicate storeViaSideEffect(Node node1, Content f, PostUpdateNode node2) {

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

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,19 @@ private newtype TNode =
2020
TInstanceParameterNode(Callable c) { exists(c.getBody()) and not c.isStatic() } or
2121
TImplicitInstanceAccess(InstanceAccessExt ia) { not ia.isExplicit(_) } or
2222
TMallocNode(ClassInstanceExpr cie) or
23-
TExplicitArgPostCall(Expr e) { explicitInstanceArgument(_, e) or e instanceof Argument } or
24-
TImplicitArgPostCall(InstanceAccessExt ia) { implicitInstanceArgument(_, ia) } or
25-
TExplicitStoreTarget(Expr e) {
26-
exists(FieldAccess fa | instanceFieldAssign(_, fa) and e = fa.getQualifier())
23+
TExplicitExprPostUpdate(Expr e) {
24+
explicitInstanceArgument(_, e)
25+
or
26+
e instanceof Argument
27+
or
28+
exists(FieldAccess fa | fa.getField() instanceof InstanceField and e = fa.getQualifier())
2729
} or
28-
TImplicitStoreTarget(InstanceAccessExt ia) {
29-
exists(FieldAccess fa | instanceFieldAssign(_, fa) and ia.isImplicitFieldQualifier(fa))
30+
TImplicitExprPostUpdate(InstanceAccessExt ia) {
31+
implicitInstanceArgument(_, ia)
32+
or
33+
exists(FieldAccess fa |
34+
fa.getField() instanceof InstanceField and ia.isImplicitFieldQualifier(fa)
35+
)
3036
}
3137

3238
/**
@@ -257,23 +263,13 @@ abstract private class ImplicitPostUpdateNode extends PostUpdateNode {
257263
override string toString() { result = getPreUpdateNode().toString() + " [post update]" }
258264
}
259265

260-
private class ExplicitArgPostCall extends ImplicitPostUpdateNode, TExplicitArgPostCall {
261-
override Node getPreUpdateNode() { this = TExplicitArgPostCall(result.asExpr()) }
262-
}
263-
264-
private class ImplicitArgPostCall extends ImplicitPostUpdateNode, TImplicitArgPostCall {
265-
override Node getPreUpdateNode() {
266-
this = TImplicitArgPostCall(result.(ImplicitInstanceAccess).getInstanceAccess())
267-
}
268-
}
269-
270-
private class ExplicitStoreTarget extends ImplicitPostUpdateNode, TExplicitStoreTarget {
271-
override Node getPreUpdateNode() { this = TExplicitStoreTarget(result.asExpr()) }
266+
private class ExplicitExprPostUpdate extends ImplicitPostUpdateNode, TExplicitExprPostUpdate {
267+
override Node getPreUpdateNode() { this = TExplicitExprPostUpdate(result.asExpr()) }
272268
}
273269

274-
private class ImplicitStoreTarget extends ImplicitPostUpdateNode, TImplicitStoreTarget {
270+
private class ImplicitExprPostUpdate extends ImplicitPostUpdateNode, TImplicitExprPostUpdate {
275271
override Node getPreUpdateNode() {
276-
this = TImplicitStoreTarget(result.(ImplicitInstanceAccess).getInstanceAccess())
272+
this = TImplicitExprPostUpdate(result.(ImplicitInstanceAccess).getInstanceAccess())
277273
}
278274
}
279275

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
public class D {
2+
Box2 boxfield;
3+
4+
public void f1() {
5+
Elem e = new Elem();
6+
Box2 b = new Box2(new Box1(null));
7+
b.box.elem = e;
8+
sinkWrap(b);
9+
}
10+
11+
public void f2() {
12+
Elem e = new Elem();
13+
Box2 b = new Box2(new Box1(null));
14+
b.box.setElem(e);
15+
sinkWrap(b);
16+
}
17+
18+
public void f3() {
19+
Elem e = new Elem();
20+
Box2 b = new Box2(new Box1(null));
21+
b.getBox1().elem = e;
22+
sinkWrap(b);
23+
}
24+
25+
public void f4() {
26+
Elem e = new Elem();
27+
Box2 b = new Box2(new Box1(null));
28+
b.getBox1().setElem(e);
29+
sinkWrap(b);
30+
}
31+
32+
public static void sinkWrap(Box2 b2) {
33+
sink(b2.getBox1().getElem());
34+
}
35+
36+
public void f5a() {
37+
Elem e = new Elem();
38+
boxfield = new Box2(new Box1(null));
39+
boxfield.box.elem = e;
40+
f5b();
41+
}
42+
43+
private void f5b() {
44+
sink(boxfield.box.elem);
45+
}
46+
47+
public static void sink(Object o) { }
48+
49+
public static class Elem { }
50+
51+
public static class Box1 {
52+
public Elem elem;
53+
public Box1(Elem e) { elem = e; }
54+
public Elem getElem() { return elem; }
55+
public void setElem(Elem e) { elem = e; }
56+
}
57+
58+
public static class Box2 {
59+
public Box1 box;
60+
public Box2(Box1 b) { box = b; }
61+
public Box1 getBox1() { return box; }
62+
public void setBox1(Box1 b) { box = b; }
63+
}
64+
}

java/ql/test/library-tests/dataflow/fields/flow.expected

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,8 @@
1919
| C.java:4:27:4:36 | new Elem(...) | C.java:19:10:19:11 | s2 |
2020
| C.java:6:28:6:37 | new Elem(...) | C.java:21:10:21:11 | s4 |
2121
| C.java:14:15:14:24 | new Elem(...) | C.java:20:10:20:11 | s3 |
22+
| D.java:5:14:5:23 | new Elem(...) | D.java:33:10:33:31 | getElem(...) |
23+
| D.java:12:14:12:23 | new Elem(...) | D.java:33:10:33:31 | getElem(...) |
24+
| D.java:19:14:19:23 | new Elem(...) | D.java:33:10:33:31 | getElem(...) |
25+
| D.java:26:14:26:23 | new Elem(...) | D.java:33:10:33:31 | getElem(...) |
26+
| D.java:37:14:37:23 | new Elem(...) | D.java:44:10:44:26 | boxfield.box.elem |

0 commit comments

Comments
 (0)