1

I am trying to use Soot to perform data flow analysis on a java file which is called Example.java.

Here is my Example.java file, my goal is to know which saySomething method animal.saySomething() will call. Here is the code for Example.java I am using:

package a1;

public class Example {
    static Animal neverCalled() {
        return new Fish();
    }
    static Animal selectAnimal() {
        return new Cat();
    }
    public static void main(String[] args) {
        Animal animal = selectAnimal();
        animal.saySomething();
    }
}
abstract class Animal {
    public abstract void saySomething();
}
class Cat extends Animal {
    public void saySomething() {
        System.out.println("purr");
    }
}
class Dog extends Animal {
    public void saySomething() {
        System.out.println("woof");
    }
}
class Fish extends Animal {
    public void saySomething() {
        System.out.println("...");
    }
}
class Car {  // not an Animal
    public void saySomething() {
        System.out.println("honk!");
    }
}

and here is the code I am using to analyze Example.java using Soot, this code is located in the file: TestSootCallGraph.java which follows here:

   package a1;

import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;

import soot.*;
import soot.jimple.Stmt;
import soot.jimple.spark.SparkTransformer;
import soot.jimple.toolkits.callgraph.CHATransformer;
import soot.jimple.toolkits.callgraph.CallGraph;
import soot.jimple.toolkits.callgraph.Targets;
import soot.options.Options;

public class TestSootCallGraph extends SceneTransformer {

    static LinkedList<String> excludeList;

    public static void main(String[] args)  {

        String mainclass = "Example";

//      //set classpath
        String javapath = System.getProperty("java.class.path");
        String jredir = System.getProperty("java.home")+"/lib/rt.jar";
        String path = javapath+File.pathSeparator+jredir;
        Scene.v().setSootClassPath(path);

            //add an intra-procedural analysis phase to Soot
        TestSootCallGraph analysis = new TestSootCallGraph();
        PackManager.v().getPack("wjtp").add(new Transform("wjtp.TestSootCallGraph", analysis));


        excludeJDKLibrary();

        //whole program analysis
        Options.v().set_whole_program(true);

            //load and set main class
        Options.v().set_app(true);
        SootClass appclass = Scene.v().loadClassAndSupport(mainclass);
        System.out.println(appclass);
        
        
        Scene.v().setMainClass(appclass);
        Scene.v().loadNecessaryClasses();


        //enable call graph
        //enableCHACallGraph();
        //enableSparkCallGraph();

            //start working
        PackManager.v().runPacks();
    }
    private static void excludeJDKLibrary()
    {
         //exclude jdk classes
        Options.v().set_exclude(excludeList());
          //this option must be disabled for a sound call graph
          Options.v().set_no_bodies_for_excluded(true);
          Options.v().set_allow_phantom_refs(true);
    }
    private static void enableSparkCallGraph() {

        //Enable Spark
          HashMap<String,String> opt = new HashMap<String,String>();
          //opt.put("propagator","worklist");
          //opt.put("simple-edges-bidirectional","false");
          opt.put("on-fly-cg","true");
          //opt.put("set-impl","double");
          //opt.put("double-set-old","hybrid");
          //opt.put("double-set-new","hybrid");
          //opt.put("pre_jimplify", "true");
          SparkTransformer.v().transform("",opt);
          PhaseOptions.v().setPhaseOption("cg.spark", "enabled:true");
    }

    private static void enableCHACallGraph() {
        CHATransformer.v().transform();
    }

    private static LinkedList<String> excludeList()
    {
        if(excludeList==null)
        {
            excludeList = new LinkedList<String> ();

            excludeList.add("java.");
            excludeList.add("javax.");
            excludeList.add("sun.");
            excludeList.add("sunw.");
            excludeList.add("com.sun.");
            excludeList.add("com.ibm.");
            excludeList.add("com.apple.");
            excludeList.add("apple.awt.");
        }
        return excludeList;
    }
    @Override
    protected void internalTransform(String phaseName,
            Map options) {

        int numOfEdges =0;

        CallGraph callGraph = Scene.v().getCallGraph();
        for(SootClass sc : Scene.v().getApplicationClasses()){
            for(SootMethod m : sc.getMethods()){

        Iterator<MethodOrMethodContext> targets = new Targets(
                 callGraph.edgesOutOf(m));

                 while (targets.hasNext()) {

                     numOfEdges++;

                SootMethod tgt = (SootMethod) targets.next();
                 System.out.println(m + " may call " + tgt);
                 }
            }
        }

         System.err.println("Total Edges:" + numOfEdges);

    }
}

I receive the following error when executing TestSootCallGraph.java which aims at analyzing Example.java. How can I fix this?

Example
Exception in thread "main" java.lang.RuntimeException: Main-class has no main method!
    at soot.Scene.setMainClass(Scene.java:171)
    at a1.TestSootCallGraph.main(TestSootCallGraph.java:47)
  • 2
    The part of soot that uses Java source code as input is as far as I know not maintained for some years. Therefore don't expect it to be functional. – JMax Nov 05 '20 at 14:53
  • @JMax what is the alternative for Soot then? – Exploring Mar 26 '21 at 23:23
  • @Exploring Sorry I don't have any experience in source code analysis. I just know that the source code reading part of Soot is not maintained. If you want to use Soot you can still compile the source code and then analyze the class files. – JMax Mar 28 '21 at 10:41

0 Answers0