javastatic-analysiscall-graphsoot

Soot: How to analyze a java file in a package?


I have two java files under the tests directory. I use the following code to set up Soot for further analysis(i.e., construct a call graph) but meet an error of are the packages set properly?.

Main.java:

public class Main {
    static void setupSoot() {
        Options.v().set_prepend_classpath(true);
        Options.v().set_process_dir(Collections.singletonList("./tests"));
        Options.v().set_whole_program(true);
        Scene.v().loadNecessaryClasses();
    }

    // Following function also doesn't work and has a similar error message
    //static void setupSoot() {
    //    Options.v().set_prepend_classpath(true);
    //    Options.v().set_process_dir(Collections.singletonList("./tests"));
    //    Scene.v().loadClassAndSupport("FooBar");
    //}

    public static void main(String[] args) {
        setupSoot();
        // ....
    }
}

And I get the following error message:

Exception in thread "main" java.lang.RuntimeException: Error: couldn't find class: FooBar are the packages set properly?
    at soot.JastAddInitialResolver.resolveFromJavaFile(JastAddInitialResolver.java:119)
    at soot.JavaClassSource.resolve(JavaClassSource.java:69)
    at soot.SootResolver.bringToHierarchyUnchecked(SootResolver.java:253)
    at soot.SootResolver.bringToHierarchy(SootResolver.java:221)
    at soot.SootResolver.bringToSignatures(SootResolver.java:292)
    at soot.SootResolver.bringToBodies(SootResolver.java:332)
    at soot.SootResolver.processResolveWorklist(SootResolver.java:171)
    at soot.SootResolver.resolveClass(SootResolver.java:141)
    at soot.Scene.loadClass(Scene.java:1009)
    at soot.Scene.loadClassAndSupport(Scene.java:994)
    at soot.Scene.loadNecessaryClasses(Scene.java:1822)
    at Main.setupSoot(Main.java:18)
    at Main.main(Main.java:21)

If I complie two test files into .class files then I will get following error message:

Exception in thread "main" soot.SootResolver$SootClassNotFoundException: couldn't find class: tests.FooBar (is your soot-class-path set properly?)
    at soot.SootResolver.bringToHierarchyUnchecked(SootResolver.java:245)
    at soot.SootResolver.bringToHierarchy(SootResolver.java:221)
    at soot.SootResolver.bringToSignatures(SootResolver.java:292)
    at soot.SootResolver.bringToBodies(SootResolver.java:332)
    at soot.SootResolver.processResolveWorklist(SootResolver.java:171)
    at soot.SootResolver.resolveClass(SootResolver.java:141)
    at soot.Scene.loadClass(Scene.java:1009)
    at soot.Scene.loadClassAndSupport(Scene.java:994)
    at soot.Scene.loadNecessaryClasses(Scene.java:1822)
    at Main.setupSoot(Main.java:18)
    at Main.main(Main.java:21)

I beleive that soot prepend_classpath is true since it works well when two test files are not in the package (i.e., remove package tests from both files).

Two files in tests directory are as follows:

Pack.java:

package tests;
public class Pack {
    public static void main(String[] args) {
        int s = 10;
    }
}

FooBar.java

package tests;

public class FooBar {
    public static void main(String[] args) {
        FooBar callFooBar = new FooBar();
        callFooBar.foo(10);
    }

    void foo(int a) {
        bar(a);
    }

    void bar(int a) {
        for (int i = 0; i < a; i++) {
            i += a;
        }
    }
}

Solution

  • I solved this problem. The issue is that the path of the test files is wrong. Now my project structure is as follows:

    -ProjectRoot
    |--src
        |--Main.java
    |--testers
        |--easycase
            |--FooBar.java
            |--Pack.java
    

    and My Main.java:

    public class Main {
        static void setupSoot() {
            Options.v().set_prepend_classpath(true);
            // Options.v().set_soot_classpath("xxxxx:xxxxx/xxxxx.jar") // For external packages
            Options.v().set_process_dir(Collections.singletonList("./testers"));
            Options.v().set_whole_program(true);
            Scene.v().loadNecessaryClasses();
        }
    
        public static void main(String[] args) {
            setupSoot();
            Scene.v().loadAndSupport("esaycase.FooBar");
            // Do something here
        }
    }
    

    Note that the first line is package easycase; for both test files.