Skip to content

Commit d3c5644

Browse files
committed
Java: Add support for in/out barriers on sources and sinks.
1 parent 143016e commit d3c5644

File tree

4 files changed

+169
-26
lines changed

4 files changed

+169
-26
lines changed

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

Lines changed: 80 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,22 @@ abstract class Configuration extends string {
103103
deprecated predicate hasFlowBackward(Node source, Node sink) { hasFlow(source, sink) }
104104
}
105105

106+
private predicate inBarrier(Node node, Configuration config) {
107+
config.isBarrier(node) and
108+
config.isSource(node)
109+
}
110+
111+
private predicate outBarrier(Node node, Configuration config) {
112+
config.isBarrier(node) and
113+
config.isSink(node)
114+
}
115+
116+
private predicate fullBarrier(Node node, Configuration config) {
117+
config.isBarrier(node) and
118+
not config.isSource(node) and
119+
not config.isSink(node)
120+
}
121+
106122
private class AdditionalFlowStepSource extends Node {
107123
AdditionalFlowStepSource() { any(Configuration c).isAdditionalFlowStep(this, _) }
108124
}
@@ -119,22 +135,47 @@ private predicate isAdditionalFlowStep(
119135
* Holds if data can flow in one local step from `node1` to `node2`.
120136
*/
121137
private predicate localFlowStep(Node node1, Node node2, Configuration config) {
122-
localFlowStep(node1, node2) and not config.isBarrierEdge(node1, node2)
138+
localFlowStep(node1, node2) and
139+
not config.isBarrierEdge(node1, node2) and
140+
not outBarrier(node1, config) and
141+
not inBarrier(node2, config) and
142+
not fullBarrier(node1, config) and
143+
not fullBarrier(node2, config)
123144
}
124145

125146
/**
126147
* Holds if the additional step from `node1` to `node2` does not jump between callables.
127148
*/
128149
private predicate additionalLocalFlowStep(Node node1, Node node2, Configuration config) {
129-
isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config)
150+
isAdditionalFlowStep(node1, node2, node2.getEnclosingCallable(), config) and
151+
not outBarrier(node1, config) and
152+
not inBarrier(node2, config) and
153+
not fullBarrier(node1, config) and
154+
not fullBarrier(node2, config)
155+
}
156+
157+
/**
158+
* Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
159+
*/
160+
private predicate jumpStep(Node node1, Node node2, Configuration config) {
161+
jumpStep(node1, node2) and
162+
not outBarrier(node1, config) and
163+
not inBarrier(node2, config) and
164+
not fullBarrier(node1, config) and
165+
not fullBarrier(node2, config)
130166
}
131167

132168
/**
133169
* Holds if the additional step from `node1` to `node2` jumps between callables.
134170
*/
135171
private predicate additionalJumpStep(Node node1, Node node2, Configuration config) {
136-
exists(DataFlowCallable callable1 | isAdditionalFlowStep(node1, node2, callable1, config) |
137-
node2.getEnclosingCallable() != callable1
172+
exists(DataFlowCallable callable1 |
173+
isAdditionalFlowStep(node1, node2, callable1, config) and
174+
node2.getEnclosingCallable() != callable1 and
175+
not outBarrier(node1, config) and
176+
not inBarrier(node2, config) and
177+
not fullBarrier(node1, config) and
178+
not fullBarrier(node2, config)
138179
)
139180
}
140181

@@ -154,7 +195,7 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKind kind) {
154195
* ignoring call contexts.
155196
*/
156197
private predicate nodeCandFwd1(Node node, boolean stored, Configuration config) {
157-
not config.isBarrier(node) and
198+
not fullBarrier(node, config) and
158199
(
159200
config.isSource(node) and stored = false
160201
or
@@ -171,7 +212,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config)
171212
or
172213
exists(Node mid |
173214
nodeCandFwd1(mid, stored, config) and
174-
jumpStep(mid, node)
215+
jumpStep(mid, node, config)
175216
)
176217
or
177218
exists(Node mid |
@@ -185,15 +226,17 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config)
185226
useFieldFlow(config) and
186227
nodeCandFwd1(mid, _, config) and
187228
store(mid, _, node) and
188-
stored = true
229+
stored = true and
230+
not outBarrier(mid, config)
189231
)
190232
or
191233
// read
192234
exists(Node mid, Content f |
193235
nodeCandFwd1(mid, true, config) and
194236
read(mid, f, node) and
195237
storeCandFwd1(f, unbind(config)) and
196-
(stored = false or stored = true)
238+
(stored = false or stored = true) and
239+
not inBarrier(node, config)
197240
)
198241
or
199242
// flow into a callable
@@ -223,7 +266,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config)
223266
*/
224267
private predicate storeCandFwd1(Content f, Configuration config) {
225268
exists(Node mid, Node node |
226-
not config.isBarrier(node) and
269+
not fullBarrier(node, config) and
227270
useFieldFlow(config) and
228271
nodeCandFwd1(mid, _, config) and
229272
store(mid, f, node)
@@ -257,7 +300,7 @@ private predicate nodeCand1(Node node, boolean stored, Configuration config) {
257300
)
258301
or
259302
exists(Node mid |
260-
jumpStep(node, mid) and
303+
jumpStep(node, mid, config) and
261304
nodeCand1(mid, stored, config)
262305
)
263306
or
@@ -318,6 +361,11 @@ private predicate readCand1(Content f, Configuration config) {
318361
)
319362
}
320363

364+
private predicate throughFlowNodeCand(Node node, Configuration config) {
365+
nodeCand1(node, false, config) and
366+
not config.isBarrier(node)
367+
}
368+
321369
/**
322370
* Holds if there is a path from `p` to `node` in the same callable that is
323371
* part of a path from a source to a sink taking simple call contexts into
@@ -329,7 +377,7 @@ pragma[nomagic]
329377
private predicate simpleParameterFlow(
330378
ParameterNode p, Node node, DataFlowType t, Configuration config
331379
) {
332-
nodeCand1(node, false, config) and
380+
throughFlowNodeCand(node, config) and
333381
p = node and
334382
t = getErasedRepr(node.getType()) and
335383
exists(ReturnNode ret, ReturnKind kind |
@@ -338,37 +386,37 @@ private predicate simpleParameterFlow(
338386
not parameterValueFlowsThrough(p, kind, _)
339387
)
340388
or
341-
nodeCand1(node, false, unbind(config)) and
389+
throughFlowNodeCand(node, unbind(config)) and
342390
exists(Node mid |
343391
simpleParameterFlow(p, mid, t, config) and
344392
localFlowStep(mid, node, config) and
345393
compatibleTypes(t, node.getType())
346394
)
347395
or
348-
nodeCand1(node, false, unbind(config)) and
396+
throughFlowNodeCand(node, unbind(config)) and
349397
exists(Node mid |
350398
simpleParameterFlow(p, mid, _, config) and
351399
additionalLocalFlowStep(mid, node, config) and
352400
t = getErasedRepr(node.getType())
353401
)
354402
or
355-
nodeCand1(node, false, unbind(config)) and
403+
throughFlowNodeCand(node, unbind(config)) and
356404
exists(Node mid |
357405
simpleParameterFlow(p, mid, t, config) and
358406
localStoreReadStep(mid, node) and
359407
compatibleTypes(t, node.getType())
360408
)
361409
or
362410
// value flow through a callable
363-
nodeCand1(node, false, unbind(config)) and
411+
throughFlowNodeCand(node, unbind(config)) and
364412
exists(Node arg |
365413
simpleParameterFlow(p, arg, t, config) and
366414
argumentValueFlowsThrough(arg, node, _) and
367415
compatibleTypes(t, node.getType())
368416
)
369417
or
370418
// flow through a callable
371-
nodeCand1(node, false, unbind(config)) and
419+
throughFlowNodeCand(node, unbind(config)) and
372420
exists(Node arg |
373421
simpleParameterFlow(p, arg, _, config) and
374422
simpleArgumentFlowsThrough(arg, node, t, config)
@@ -380,6 +428,7 @@ private predicate simpleArgumentFlowsThrough0(
380428
DataFlowCall call, ArgumentNode arg, ReturnKind kind, DataFlowType t, Configuration config
381429
) {
382430
nodeCand1(arg, false, unbind(config)) and
431+
not outBarrier(arg, config) and
383432
exists(ParameterNode p, ReturnNode ret |
384433
simpleParameterFlow(p, ret, t, config) and
385434
kind = ret.getKind() and
@@ -399,6 +448,7 @@ private predicate simpleArgumentFlowsThrough(
399448
) {
400449
exists(DataFlowCall call, ReturnKind kind |
401450
nodeCand1(out, false, unbind(config)) and
451+
not inBarrier(out, config) and
402452
simpleArgumentFlowsThrough0(call, arg, kind, t, config) and
403453
out = getAnOutNode(call, kind)
404454
)
@@ -440,6 +490,8 @@ private predicate additionalLocalFlowStepOrFlowThroughCallable(
440490
private predicate flowOutOfCallable(Node node1, Node node2, Configuration config) {
441491
nodeCand1(node1, _, unbind(config)) and
442492
nodeCand1(node2, _, config) and
493+
not outBarrier(node1, config) and
494+
not inBarrier(node2, config) and
443495
(
444496
// flow out of an argument
445497
exists(ParameterNode p |
@@ -462,7 +514,9 @@ private predicate flowOutOfCallable(Node node1, Node node2, Configuration config
462514
private predicate flowIntoCallable(Node node1, Node node2, Configuration config) {
463515
viableParamArg(_, node2, node1) and
464516
nodeCand1(node1, _, unbind(config)) and
465-
nodeCand1(node2, _, config)
517+
nodeCand1(node2, _, config) and
518+
not outBarrier(node1, config) and
519+
not inBarrier(node2, config)
466520
}
467521

468522
/**
@@ -546,7 +600,7 @@ private predicate nodeCandFwd2(Node node, boolean fromArg, boolean stored, Confi
546600
or
547601
exists(Node mid |
548602
nodeCandFwd2(mid, _, stored, config) and
549-
jumpStep(mid, node) and
603+
jumpStep(mid, node, config) and
550604
fromArg = false
551605
)
552606
or
@@ -626,7 +680,7 @@ private predicate nodeCand2(Node node, boolean toReturn, boolean stored, Configu
626680
)
627681
or
628682
exists(Node mid |
629-
jumpStep(node, mid) and
683+
jumpStep(node, mid, config) and
630684
nodeCand2(mid, _, stored, config) and
631685
toReturn = false
632686
)
@@ -714,7 +768,7 @@ private predicate localFlowEntry(Node node, Configuration config) {
714768
nodeCand(node, config) and
715769
(
716770
config.isSource(node) or
717-
jumpStep(_, node) or
771+
jumpStep(_, node, config) or
718772
additionalJumpStep(_, node, config) or
719773
node instanceof ParameterNode or
720774
node instanceof OutNode or
@@ -730,7 +784,7 @@ private predicate localFlowEntry(Node node, Configuration config) {
730784
*/
731785
private predicate localFlowExit(Node node, Configuration config) {
732786
exists(Node next | nodeCand(next, config) |
733-
jumpStep(node, next) or
787+
jumpStep(node, next, config) or
734788
additionalJumpStep(node, next, config) or
735789
flowIntoCallable(node, next, config) or
736790
flowOutOfCallable(node, next, config) or
@@ -882,7 +936,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
882936
or
883937
exists(Node mid |
884938
flowCandFwd(mid, _, apf, config) and
885-
jumpStep(mid, node) and
939+
jumpStep(mid, node, config) and
886940
fromArg = false
887941
)
888942
or
@@ -973,7 +1027,7 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
9731027
)
9741028
or
9751029
exists(Node mid |
976-
jumpStep(node, mid) and
1030+
jumpStep(node, mid, config) and
9771031
flowCand(mid, _, apf, config) and
9781032
toReturn = false
9791033
)
@@ -1154,7 +1208,7 @@ private predicate flowFwd0(
11541208
or
11551209
exists(Node mid |
11561210
flowFwd(mid, _, apf, ap, config) and
1157-
jumpStep(mid, node) and
1211+
jumpStep(mid, node, config) and
11581212
fromArg = false
11591213
)
11601214
or
@@ -1263,7 +1317,7 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
12631317
)
12641318
or
12651319
exists(Node mid |
1266-
jumpStep(node, mid) and
1320+
jumpStep(node, mid, config) and
12671321
flow(mid, _, ap, config) and
12681322
toReturn = false
12691323
)
@@ -1518,7 +1572,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPat
15181572
mid.getAp() instanceof AccessPathNil and
15191573
ap = node.(AccessPathNilNode).getAp()
15201574
or
1521-
jumpStep(mid.getNode(), node) and
1575+
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
15221576
cc instanceof CallContextAny and
15231577
ap = mid.getAp()
15241578
or
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class A {
2+
static String fsrc = "";
3+
4+
String src(String s) { return s; }
5+
6+
void sink(String s) { }
7+
8+
void foo() {
9+
String s = fsrc;
10+
sink(fsrc);
11+
12+
s = src(s);
13+
sink(s);
14+
15+
sink(s);
16+
}
17+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
| A.java:9:16:9:19 | fsrc | A.java:13:10:13:10 | s | nobarrier, sinkbarrier |
2+
| A.java:9:16:9:19 | fsrc | A.java:15:10:15:10 | s | nobarrier |
3+
| A.java:10:10:10:13 | fsrc | A.java:10:10:10:13 | fsrc | both, nobarrier, sinkbarrier, srcbarrier |
4+
| A.java:12:9:12:14 | src(...) | A.java:13:10:13:10 | s | both, nobarrier, sinkbarrier, srcbarrier |
5+
| A.java:12:9:12:14 | src(...) | A.java:15:10:15:10 | s | nobarrier, srcbarrier |

0 commit comments

Comments
 (0)