SootUp icon indicating copy to clipboard operation
SootUp copied to clipboard

Unexpected Clinit calls in the call graph

Open kitty-1998 opened this issue 1 year ago • 3 comments

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 method.

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

kitty-1998 avatar Apr 02 '24 10:04 kitty-1998

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

JonasKlauke avatar Apr 08 '24 08:04 JonasKlauke

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.

kitty-1998 avatar Apr 09 '24 08:04 kitty-1998

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

JonasKlauke avatar Apr 09 '24 12:04 JonasKlauke