soot-oss / SootUp

A new version of Soot with a completely overhauled architecture
https://soot-oss.github.io/SootUp/
GNU Lesser General Public License v2.1
551 stars 66 forks source link

Support MethodHandle Resolve in Callgraph Algorithm #906

Open tisble opened 3 months ago

tisble commented 3 months ago

Hi, I used SootUp to analyze the following code example from my project and found a bug abou handling lambda invocation:

package org.me;
public class Test {
    public void m1() {
        Runnable runnable = this::m2;
        runnable.run();  // invoke m2
    }
    public void m2() {
        System.out.println("m2");
    }
}

Considering line 4 and line 7, SootUp should report an edge from m1 to m2, but it missed.

Version: develop-5af272dcda

My Code to Invoke SootUp

AnalysisInputLocation javaBaseInputLocation = new JavaClassPathAnalysisInputLocation("JDK_PATH", SourceType.Library);
AnalysisInputLocation classInput = new JavaClassPathAnalysisInputLocation("INPUT_PATH", SourceType.Application);
ArrayList<AnalysisInputLocation> allInput=new ArrayList<>();
allInput.add(classInput);
allInput.add(javaBaseInputLocation);
JavaView view = new JavaView(allInput);

List<String> EntrySignatures=new ArrayList<>();
EntrySignatures.add("<org.me.Test: void m1()>");
EntrySignatures.add("<org.me.Test: void m2()>");
List<MethodSignature> entryMethods = new ArrayList<>();
for(String EntrySignature:EntrySignatures){
    for (JavaSootClass klass : view.getClasses()) {
        for (JavaSootMethod method : klass.getMethods()) {
            if (method.getSignature().toString().equals(EntrySignature)) {
                entryMethods.add(method.getSignature());
            }
        }
    }
}
CallGraphAlgorithm rta = new RapidTypeAnalysisAlgorithm(view);
CallGraph cg = rta.initialize(entryMethods);
JonasKlauke commented 3 months ago

that is an indirect edge which is currently not covered. I even wonder how other static analysis frameworks perform on this code

tisble commented 3 months ago

Hi @JonasKlauke. I tried Wala and found it can generate the following edges to build the call:

org.me.Test.m1()V --> wala.lambda$org$me$Test$0.run()V wala.lambda$org$me$Test$0.run()V --> org.me.Test.m2()V

It seems that Wala can handle the lambda here. Hope this can help you.

JonasKlauke commented 3 months ago
 public void m1();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=2, args_size=1
         0: aload_0
         1: invokedynamic #2,  0              // InvokeDynamic #0:run:(LTest;)Ljava/lang/Runnable;
         6: astore_1
         7: aload_1
         8: invokeinterface #3,  1            // InterfaceMethod java/lang/Runnable.run:()V
        13: return

BootstrapMethods:
  0: #19 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
    Method arguments:
      #20 ()V
      #21 invokevirtual Test.m2:()V
      #20 ()V

If you look at the bytecode you see that m2 is not called directly. A methodhandle is created and you see as one of the Method arguments that Test.m2 is called. SootUp currently does not support MethodHandle resolving. Wala seems to have already some MethodHandle support.

JonasKlauke commented 3 months ago

A similar issue is shown in #917