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
593 stars 81 forks source link

Java 11 support #562

Closed lehvolk closed 1 year ago

lehvolk commented 1 year ago

Is Java 11 supported?

I run this code under Java 11 and it's returned empty Optional


val allRuntimeLocations: List<File>
    get() {
        val javaHome = File(System.getProperty("java.home"))
        return Paths.get(javaHome.toPath().toString(), "jmods").toFile()
            .listFiles { file -> file.name.endsWith(".jar") || file.name.endsWith(".jmod") }
            .orEmpty()
            .toList()
    }

fun main() {
    val javaHome = System.getProperty("java.home")
    println(javaHome)

    val classpath = System.getProperty("java.class.path")
    val cp = classpath.split(File.pathSeparator.toRegex()).map { File(it) }
    val builder: JavaProject.JavaProjectBuilder = JavaProject.builder(JavaLanguage(11))

    allRuntimeLocations.forEach {
        println(it.absolutePath)
        builder.addInputLocation(JavaModulePathAnalysisInputLocation(it.absolutePath))
    }

    for (s in cp) {
        if (s.exists()) {
            builder.addInputLocation(JavaModulePathAnalysisInputLocation(s.absolutePath))
        }
    }
    val javaProject: JavaProject = builder.build()
    val view = javaProject.createFullView()

    val identifierFactory = JavaModuleIdentifierFactory.getInstance()
    val type = identifierFactory.getClassType("java.lang.String")

    view.getClass(type) <-- IS EMPTY

}
kadirayk commented 1 year ago

Hi,

yes, we support Java 11. Could you try again by adding these two things:

  1. builder.addInputLocation(new JrtFileSystemAnalysisInputLocation());
  2. identifierFactory.getClassType("java.base/java.lang.String");
lehvolk commented 1 year ago

But this requires running on Java 11, right? Otherwise JrtFileSystemAnalysisInputLocation throws Exception.

lehvolk commented 1 year ago

I stuck a bit with second option but seems that code do a trick:

fun main() {
    val javaHome = "C:\\Program Files\\ojdkbuild\\java-11-openjdk-11.0.15-1"
    println(javaHome)

    val classpath = System.getProperty("java.class.path")
    val cp = classpath.split(File.pathSeparator.toRegex()).map { File(it) }
    val builder: JavaProject.JavaProjectBuilder = JavaProject.builder(JavaLanguage(11))

    allRuntimeLocations.forEach {
        println(it.absolutePath)
        builder.addInputLocation(JavaModulePathAnalysisInputLocation(it.absolutePath))
    }

    for (s in cp) {
        if (s.exists()) {
            builder.addInputLocation(JavaModulePathAnalysisInputLocation(s.absolutePath))
        }
    }
    val javaProject: JavaProject = builder.build()
    val view = javaProject.createFullView()

    val identifierFactory = JavaModuleIdentifierFactory.getInstance()
    val type = identifierFactory.getClassType("java.lang.String")

    val sootClass = view.getClass(type)
    println(sootClass.get().methods.first().body)
}
JonasKlauke commented 1 year ago

Because Java11 uses modules, the fully quailfied name of a class is defined by the module and the path. java.base is the module and java.lang the package. To get the correct ClassType, you have to use "java.base/java.lang.String"

swissiety commented 1 year ago

But this requires running on Java 11, right? Otherwise JrtFileSystemAnalysisInputLocation throws Exception.

It needs at least Java9 where JavaModules was introduced (so we could make use of the java class library to access the modules etc.).

lehvolk commented 1 year ago

To get the correct ClassType, you have to use "java.base/java.lang.String"

@JonasKlauke It was my first variant but I got empty Optional for this code:

    val identifierFactory = JavaModuleIdentifierFactory.getInstance()
    val type = identifierFactory.getClassType("java.base/java.lang.String")

Here is a full gist for this https://gist.github.com/lehvolk/25e906a414bb5054df28bcb2f2152c2f

Then I removed "java.base/" and everything works. Current behavior contradicts your statement about modules names.

PS Just in case I'm running this code on Java 8

swissiety commented 1 year ago

ok running from Java8 we cant access the module specific functionality. Without specifying a module signatue (like java.base/...) a usual (read: like <Java9) ClassType is created in the javaidentifierfactory. Every input that is not assigned to a module is collected into the unnamed module so it is accessed without the module package name in the signature.

Beware: It seems java.lang.String comes from the rt.jar of your java8 which could have a different implementations to the java11 code you want to analyze