Skip to content

Commit 8710d8b

Browse files
committed
Disallow null in QueueReader to handle concurrency correctly
Before that, it could happen that the QueueReader's hasNext method is called, and then the corresponding element gets invalidated by another thread. In that case, the next method throw a NoSuchElement exce> Instead (and conforming to to the JavaDoc), we allow null to be returned in these cases. This means that ChunkedQueues may not contain actual nulls anymore.
1 parent ce190f1 commit 8710d8b

13 files changed

+51
-17
lines changed

src/main/java/soot/MethodToContexts.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ public MethodToContexts(Iterator<MethodOrMethodContext> it) {
5555
public void add(Iterator<MethodOrMethodContext> it) {
5656
while (it.hasNext()) {
5757
MethodOrMethodContext momc = it.next();
58-
add(momc);
58+
if (momc != null) {
59+
add(momc);
60+
}
5961
}
6062
}
6163

src/main/java/soot/jimple/spark/builder/ContextInsensitiveBuilder.java

+6-3
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,14 @@ public void build() {
104104
}
105105
while (callEdges.hasNext()) {
106106
Edge e = callEdges.next();
107+
if (e == null) {
108+
continue;
109+
}
107110
if (!e.isInvalid()) {
108111
if (e.tgt().isConcrete() || e.tgt().isNative()) {
109-
MethodPAG mpag = MethodPAG.v(pag, e.tgt());
110-
mpag.build();
111-
mpag.addToPAG(null);
112+
MethodPAG mpag = MethodPAG.v(pag, e.tgt());
113+
mpag.build();
114+
mpag.addToPAG(null);
112115
}
113116
pag.addCallTarget(e);
114117
}

src/main/java/soot/jimple/spark/geom/geomPA/GeomPointsTo.java

+6-2
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,11 @@ private void preprocess() {
359359
CallGraph soot_callgraph = Scene.v().getCallGraph();
360360

361361
while (smList.hasNext()) {
362-
final SootMethod func = smList.next().method();
362+
MethodOrMethodContext n = smList.next();
363+
if (n == null) {
364+
continue;
365+
}
366+
final SootMethod func = n.method();
363367
func2int.put(func, id);
364368
int2func.put(id, func);
365369

@@ -385,7 +389,7 @@ private void preprocess() {
385389
QueueReader<Edge> edgeList = Scene.v().getCallGraph().listener();
386390
while (edgeList.hasNext()) {
387391
Edge edge = edgeList.next();
388-
if (edge.isClinit()) {
392+
if (edge == null || edge.isClinit()) {
389393
continue;
390394
}
391395

src/main/java/soot/jimple/spark/internal/TypeManager.java

+3
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ final public BitVector get(Type type) {
115115
final Scene sc = Scene.v();
116116
while (allocNodeListener.hasNext()) {
117117
AllocNode n = allocNodeListener.next();
118+
if (n == null) {
119+
continue;
120+
}
118121
Type nt = n.getType();
119122
Iterable<Type> types;
120123
if (nt instanceof NullType || nt instanceof AnySubType) {

src/main/java/soot/jimple/spark/solver/OnFlyCallGraph.java

+6
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@ private void processReachables() {
111111
reachableMethods.update();
112112
while (reachablesReader.hasNext()) {
113113
MethodOrMethodContext m = reachablesReader.next();
114+
if (m == null) {
115+
continue;
116+
}
114117
MethodPAG mpag = MethodPAG.v(pag, m.method());
115118
try {
116119
mpag.build();
@@ -129,6 +132,9 @@ private void processReachables() {
129132
private void processCallEdges() {
130133
while (callEdges.hasNext()) {
131134
Edge e = callEdges.next();
135+
if (e == null) {
136+
continue;
137+
}
132138
MethodPAG amp = MethodPAG.v(pag, e.tgt());
133139
amp.build();
134140
amp.addToPAG(e.tgtCtxt());

src/main/java/soot/jimple/toolkits/callgraph/CallGraph.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.util.LinkedHashMap;
3030
import java.util.LinkedHashSet;
3131
import java.util.Map;
32+
import java.util.NoSuchElementException;
3233
import java.util.Set;
3334

3435
import soot.Kind;
@@ -99,7 +100,7 @@ public boolean removeAllEdgesOutOf(Unit u) {
99100
Set<Edge> edgesToRemove = new HashSet<>();
100101
for (QueueReader<Edge> edgeRdr = listener(); edgeRdr.hasNext();) {
101102
Edge e = edgeRdr.next();
102-
if (e.srcUnit() == u) {
103+
if (e != null && e.srcUnit() == u) {
103104
e.remove();
104105
removeEdge(e, false);
105106
edgesToRemove.add(e);
@@ -395,7 +396,9 @@ public String toString() {
395396
StringBuilder out = new StringBuilder();
396397
for (QueueReader<Edge> reader = listener(); reader.hasNext();) {
397398
Edge e = reader.next();
398-
out.append(e.toString()).append('\n');
399+
if (e != null) {
400+
out.append(e.toString()).append('\n');
401+
}
399402
}
400403
return out.toString();
401404
}

src/main/java/soot/jimple/toolkits/callgraph/CallGraphBuilder.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ public void build() {
111111
break;
112112
}
113113
final MethodOrMethodContext momc = worklist.next();
114-
if (!process(momc)) {
114+
if (momc != null && !process(momc)) {
115115
break;
116116
}
117117
}

src/main/java/soot/jimple/toolkits/callgraph/Filter.java

+3
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ public Iterator<Edge> wrap(Iterator<Edge> source) {
4848
private void advance() {
4949
while (source.hasNext()) {
5050
next = source.next();
51+
if (next == null) {
52+
continue;
53+
}
5154
if (pred.want(next)) {
5255
return;
5356
}

src/main/java/soot/jimple/toolkits/callgraph/OnFlyCallGraphBuilder.java

+3
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,9 @@ public void processReachables() {
279279
}
280280
}
281281
MethodOrMethodContext momc = worklist.next();
282+
if (momc == null) {
283+
continue;
284+
}
282285
SootMethod m = momc.method();
283286
if (appOnly && !m.getDeclaringClass().isApplicationClass()) {
284287
continue;

src/main/java/soot/jimple/toolkits/callgraph/ReachableMethods.java

+4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.Collection;
2626
import java.util.HashSet;
2727
import java.util.Iterator;
28+
import java.util.NoSuchElementException;
2829
import java.util.Set;
2930

3031
import soot.MethodOrMethodContext;
@@ -89,6 +90,9 @@ public void update() {
8990
}
9091
while (unprocessedMethods.hasNext()) {
9192
MethodOrMethodContext m = unprocessedMethods.next();
93+
if (m == null) {
94+
continue;
95+
}
9296
Iterator<Edge> targets = cg.edgesOutOf(m);
9397
if (filter != null) {
9498
targets = filter.wrap(targets);

src/main/java/soot/jimple/toolkits/callgraph/SlowCallGraph.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,9 @@ public String toString() {
134134
StringBuilder out = new StringBuilder();
135135
for (QueueReader<Edge> rdr = listener(); rdr.hasNext();) {
136136
Edge e = rdr.next();
137-
out.append(e.toString()).append('\n');
137+
if (e != null) {
138+
out.append(e.toString()).append('\n');
139+
}
138140
}
139141
return out.toString();
140142
}

src/main/java/soot/util/queue/ChunkedQueue.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
@SuppressWarnings("unchecked")
3434
public class ChunkedQueue<E> {
3535

36-
protected static final Object NULL_CONST = new Object();
3736
protected static final Object DELETED_CONST = new Object();
3837

3938
protected static final int LENGTH = 60;
@@ -48,7 +47,7 @@ public ChunkedQueue() {
4847
/** Add an object to the queue. */
4948
public void add(E o) {
5049
if (o == null) {
51-
o = (E) NULL_CONST;
50+
throw new IllegalArgumentException("Null is not allowed");
5251
}
5352
if (index == LENGTH - 1) {
5453
Object[] temp = new Object[LENGTH];

src/main/java/soot/util/queue/QueueReader.java

+7-5
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
* been read by all the QueueReader's are kept. A QueueReader only receives the Object's added to the queue <b>after</b> the
3636
* QueueReader was created.
3737
*
38+
* This QueueReader does <emph>not</emph> accept <code>null</code> values.
3839
* @author Ondrej Lhotak
3940
*/
4041
public class QueueReader<E> implements java.util.Iterator<E> {
@@ -54,19 +55,20 @@ public E next() {
5455
Object ret = null;
5556
do {
5657
if (q[index] == null) {
57-
throw new NoSuchElementException();
58+
//this is the case when someone concurrently invalidates
59+
//the rest of the elements
60+
return null;
5861
}
5962
if (index == q.length - 1) {
6063
q = (E[]) q[index];
6164
index = 0;
6265
if (q[index] == null) {
63-
throw new NoSuchElementException();
66+
//this is the case when someone concurrently invalidates
67+
//the rest of the elements
68+
return null;
6469
}
6570
}
6671
ret = q[index];
67-
if (ret == ChunkedQueue.NULL_CONST) {
68-
ret = null;
69-
}
7072
index++;
7173
} while (skip(ret));
7274
return (E) ret;

0 commit comments

Comments
 (0)