soot
soot copied to clipboard
ConcurrentModificationException when using Options.v().set_ignore_resolution_errors(true);
I got below exception
java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901) at java.util.ArrayList$Itr.next(ArrayList.java:851) at soot.jimple.toolkits.annotation.LineNumberAdder.internalTransform(LineNumberAdder.java:58) at soot.PackManager.runPacksNormally(PackManager.java:491) at soot.PackManager.runPacks(PackManager.java:419) at soot.Main.run(Main.java:269) at soot.Main.main(Main.java:141)
when i set Options.v().set_ignore_resolution_errors(true);
How can i solve this problem ?
Any updates on this ?
I have a very small reproducer for this
cat C.java I.java && javac C.java I.java && jar cf C.jar C.class && java -cp ... soot.Main -process-dir C.jar -keep-line-number -ignore-resolution-errors -allow-phantom-refs
abstract class C implements I {
void bar() {
try {
foo();
} catch (Exception e) {
throw e;
}
}
}
interface I {
void foo();
}
Soot started on Fri Jul 01 19:34:23 UTC 2022
java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1013)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:967)
at soot.jimple.toolkits.annotation.LineNumberAdder.internalTransform(LineNumberAdder.java:57)
at soot.PackManager.runPacksNormally(PackManager.java:496)
at soot.PackManager.runPacks(PackManager.java:425)
at soot.Main.run(Main.java:280)
at soot.Main.main(Main.java:142)
And here is my rough understanding of the root cause:
- line number adder iterates over the methods of class C
- runs jb pack on body of bar, including the unreachable code eliminator (uce)
- uce creates an exceptional unit graph for bar, initializing exception destinations using unit throw analysis
- unit throw analysis processes method references, trying to resolve foo
- foo cannot be resolved, as it is defined in interface I which is not included in input jars
- fallback logic in soot method ref impl creates an artificial method for foo in class C
- now the list of methods for class C has changed, causing the concurrent modification exception in line number adder
It seems like there are at least two approaches to avoid CME here:
- iterate over snapshot(s) of method list, or
- do not change method list.
For the first, one should decide whether to include newly-added methods, e.g., by continuing until snapshots stabilize.
For the second, I am wondering: should the declaration of method foo
be added to class C
, or is that the bug?
@linghuiluo @StevenArzt @mbenz89 any thoughts about the above?
I would go for the first approach, i.e., create a copy of the method list. Only phantom methods should be created during the (transitive) method resolving started by the LineNumberAdder
, and there's nothing to add in those.
Only phantom methods should be created during the (transitive) method resolving started by the LineNumberAdder
But should phantom methods be added to the class for which bodies are already loaded?
In this example, class C does not declare method foo, yet foo gets added as a phantom method to class C. Should this be happening?
Yes, the method should be added. There are two scenarios: Phantom methods are disabled, and an error is thrown. Or phantom methods are enabled and these methods get added whenever Soot encounters a reference to a method that does not exist. More precisely, the phantom method gets added as soon as someone resolves the respective method reference (getMethod()
on the reference in the InvokeExpr
). Even if the bodies are loaded, that doesn't mean that all transitive references are resolved, it just means that the invocation is there, referencing some method that might or might not exist (to be resolved later).