Unexpected Clinit calls in the call graph
Hi, I used SootUp to analyze some projects and found false positives which affect my analysis results. After, investigation, I found the following minimized code example:
package org.example;
public class C {
private static final String CName = C.class.getName();
public void foo(){}
}
SootUp reports an edge from <org.example.C: void foo()> to <org.example.C: void <clinit>()>, which is incorrect. It seems that this bug is related to the initialization of
SootUp configuration
AnalysisInputLocation<JavaSootClass> javaBaseInputLocation = new JavaClassPathAnalysisInputLocation("Path/to/javaBase", SourceType.Library);
AnalysisInputLocation<JavaSootClass> classInput = new JavaClassPathAnalysisInputLocation("Path/to/classDir", SourceType.Application);
JavaProject project = JavaProject.builder(new JavaLanguage(8))
.addInputLocation(classInput)
.addInputLocation(javaBaseInputLocation)
.build();
JavaView view = project.createView();
CallGraph cg;
String EntrySignature="<org.example.C: void foo()>"
List<MethodSignature> entryMethods = new ArrayList<>();
for (JavaSootClass klass : classes) {
for (JavaSootMethod method : klass.getMethods()) {
if (method.getSignature().toString().equals(EntrySignature)) {
entryMethods.add(method.getSignature());
}
}
}
CallGraphAlgorithm cha = new ClassHierarchyAnalysisAlgorithm(Constants.view);
CallGraph cg = cha.initialize(entryMethods);
SootUp version: 1.1.2
Hi Kitty, yes you are correct this edge is not correct. But the reason for this edge is to not miss the static initializer. The call graph algorithm will add an edge to the static initializer for every entry method, since if the method is the start of an application, the static initializer would be called before the this method is called. So the idea of this edge is that before the first statement the static initializer is called. The edge to a static initializer is quite hard to define precisely, since the static initializer is called the first time a class is used. Therefore everytime a construtor is called, a static method is called, and a static field is accessed, there will be an edge to a clinit method, because the call graph algorithm is flow insensitive. It would need flow sensitive post processing to remove duplicate clinit calls.
So to sum up this is not a bug this is a feature 😄 but we could think about an option to disable indirect calls in the call graph
Hi, thanks for your reply. This is a good design, but adding an edge from entry to clinit seems violates the executation order as you said <clinit> is executed before the entries.
So, I think directly adding the <clinit> to the entry methods (controlled by the option) instead maybe a good choice? 😃 , but it may introduce extra overhead for analysis.
The correct solution would be to don't connect them at all and introduce a new entry point to the call graph, but I think then it could be forgotten. An other option would be that the clinit method calls the entry method, but i think then it would be ignored also since the entry point is moved to the clinit So I'm not quite sure how to resolve this issue. I think old soot also added this edge to the entry method