Skip to content

Commit

Permalink
Add support for fields
Browse files Browse the repository at this point in the history
  • Loading branch information
oxisto committed Jan 1, 2024
1 parent 5aefa06 commit 6de25da
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ import de.fraunhofer.aisec.cpg.graph.*
import de.fraunhofer.aisec.cpg.graph.declarations.*
import sootup.core.jimple.basic.Local
import sootup.core.model.SootClass
import sootup.core.model.SootField
import sootup.core.model.SootMethod
import sootup.java.core.JavaSootClass
import sootup.java.core.JavaSootField
import sootup.java.core.JavaSootMethod
import sootup.java.core.jimple.basic.JavaLocal

Expand All @@ -41,6 +43,8 @@ class DeclarationHandler(frontend: JVMLanguageFrontend) :
map.put(JavaSootClass::class.java) { handleClass(it as SootClass<*>) }
map.put(SootMethod::class.java) { handleMethod(it as SootMethod) }
map.put(JavaSootMethod::class.java) { handleMethod(it as SootMethod) }
map.put(SootField::class.java) { handleField(it as SootField) }
map.put(JavaSootField::class.java) { handleField(it as SootField) }
map.put(Local::class.java) { handleLocal(it as Local) }
map.put(JavaLocal::class.java) { handleLocal(it as Local) }
}
Expand All @@ -51,6 +55,12 @@ class DeclarationHandler(frontend: JVMLanguageFrontend) :
// Enter the class scope
frontend.scopeManager.enterScope(record)

// Loop through all fields
for (sootField in sootClass.getFields()) {
val field = handle(sootField)
frontend.scopeManager.addDeclaration(field)
}

// Loop through all methods
for (sootMethod in sootClass.getMethods()) {
val method = handle(sootMethod)
Expand Down Expand Up @@ -102,6 +112,15 @@ class DeclarationHandler(frontend: JVMLanguageFrontend) :
return method
}

fun handleField(field: SootField): FieldDeclaration {
return newFieldDeclaration(
field.name,
frontend.typeOf(field.type),
field.modifiers.map { it.name.lowercase() },
rawNode = field
)
}

private fun handleLocal(local: Local): VariableDeclaration {
return newVariableDeclaration(local.name, frontend.typeOf(local.type), rawNode = local)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,12 @@ import sootup.core.jimple.common.expr.JNewExpr
import sootup.core.jimple.common.expr.JSpecialInvokeExpr
import sootup.core.jimple.common.expr.JStaticInvokeExpr
import sootup.core.jimple.common.expr.JVirtualInvokeExpr
import sootup.core.jimple.common.ref.JInstanceFieldRef
import sootup.core.jimple.common.ref.JParameterRef
import sootup.core.jimple.common.ref.JStaticFieldRef
import sootup.core.jimple.common.ref.JThisRef
import sootup.core.signatures.MethodSignature
import sootup.core.signatures.SootClassMemberSignature
import sootup.java.core.jimple.basic.JavaLocal

class ExpressionHandler(frontend: JVMLanguageFrontend) :
Expand All @@ -57,6 +59,7 @@ class ExpressionHandler(frontend: JVMLanguageFrontend) :
map.put(JavaLocal::class.java) { handleLocal(it as Local) }
map.put(JThisRef::class.java) { handleThisRef(it as JThisRef) }
map.put(JParameterRef::class.java) { handleParameterRef(it as JParameterRef) }
map.put(JInstanceFieldRef::class.java) { handleInstanceFieldRef(it as JInstanceFieldRef) }
map.put(JStaticFieldRef::class.java) { handleStaticFieldRef(it as JStaticFieldRef) }
map.put(JVirtualInvokeExpr::class.java) {
handleVirtualInvokeExpr(it as JVirtualInvokeExpr)
Expand All @@ -80,7 +83,7 @@ class ExpressionHandler(frontend: JVMLanguageFrontend) :

lit
} else {
val ref = newReference(local.name, rawNode = local)
val ref = newReference(local.name, frontend.typeOf(local.type), rawNode = local)

ref
}
Expand All @@ -103,24 +106,24 @@ class ExpressionHandler(frontend: JVMLanguageFrontend) :
return ref
}

private fun handleStaticFieldRef(staticFieldRef: JStaticFieldRef): Reference {
// TODO(oxisto): not sure if this shouldn't be a regular reference instead
val base =
newReference(
staticFieldRef.fieldSignature.declClassType.fullyQualifiedName,
frontend.typeOf(staticFieldRef.fieldSignature.declClassType)
)
private fun handleInstanceFieldRef(instanceFieldRef: JInstanceFieldRef): Reference {
val base = handle(instanceFieldRef.base) ?: newProblemExpression("missing base")

val expr =
val ref =
newMemberExpression(
staticFieldRef.fieldSignature.name,
instanceFieldRef.fieldSignature.name,
base,
frontend.typeOf(staticFieldRef.type),
rawNode = staticFieldRef
frontend.typeOf(instanceFieldRef.fieldSignature.type),
rawNode = instanceFieldRef
)
expr.isStaticAccess = true

return expr
return ref
}

private fun handleStaticFieldRef(staticFieldRef: JStaticFieldRef): Reference {
val ref = staticFieldRef.fieldSignature.toStaticRef()

return ref
}

private fun handleVirtualInvokeExpr(
Expand Down Expand Up @@ -205,7 +208,7 @@ class ExpressionHandler(frontend: JVMLanguageFrontend) :

private fun MethodSignature.toStaticRef(): Reference {
// First, construct the name using <parent-type>.<fun>
val ref = newReference("${this.declClassType.fullyQualifiedName}.${this.name}")
val ref = (this as SootClassMemberSignature<*>).toStaticRef()

// We can also provide a function type, since these are all statically known. This might
// help in inferring some (unknown) functions later
Expand All @@ -217,6 +220,13 @@ class ExpressionHandler(frontend: JVMLanguageFrontend) :
frontend.language
)

return ref
}

private fun SootClassMemberSignature<*>.toStaticRef(): Reference {
// First, construct the name using <parent-type>.<fun>
val ref = newReference("${this.declClassType.fullyQualifiedName}.${this.name}")

// Make it static
ref.isStaticAccess = true

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import kotlin.reflect.KClass

class JVMLanguage : Language<JVMLanguageFrontend>() {
override val fileExtensions: List<String>
get() = listOf("class", "jimple")
get() = listOf("class", "java", "jimple")

override val namespaceDelimiter: String
get() = "."
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import sootup.core.types.UnknownType
import sootup.java.bytecode.inputlocation.JavaClassPathAnalysisInputLocation
import sootup.java.core.JavaSootClass
import sootup.java.core.views.JavaView
import sootup.java.sourcecode.inputlocation.JavaSourcePathAnalysisInputLocation

typealias SootType = sootup.core.types.Type

Expand Down Expand Up @@ -73,9 +74,18 @@ class JVMLanguageFrontend(
val project = JavaProject.builder(language).addInputLocation(inputLocation).build()
project.createView()
}*/
val inputLocation: AnalysisInputLocation<JavaSootClass> =
JavaClassPathAnalysisInputLocation(ctx.config.topLevel!!.path)
val view = JavaView(inputLocation)
val view =
if (file.extension == "class") {
val inputLocation: AnalysisInputLocation<JavaSootClass> =
JavaClassPathAnalysisInputLocation(ctx.config.topLevel!!.path)
JavaView(inputLocation)
} else if (file.extension == "java") {
val inputLocation: AnalysisInputLocation<JavaSootClass> =
JavaSourcePathAnalysisInputLocation(ctx.config.topLevel!!.path)
JavaView(inputLocation)
} else {
throw TranslationException("unsupported file")
}

// This contains the whole directory
val tu = newTranslationUnitDeclaration(file.parent)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import de.fraunhofer.aisec.cpg.assertLocalName
import de.fraunhofer.aisec.cpg.graph.*
import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression
import de.fraunhofer.aisec.cpg.graph.statements.expressions.MemberCallExpression
import de.fraunhofer.aisec.cpg.graph.statements.expressions.MemberExpression
import de.fraunhofer.aisec.cpg.passes.EdgeCachePass
import de.fraunhofer.aisec.cpg.passes.astParent
import java.nio.file.Path
Expand Down Expand Up @@ -147,12 +148,12 @@ class JVMLanguageFrontendTest {
}

@Test
fun testLiterals() {
fun testLiteralsClass() {
// This will be our classpath
val topLevel = Path.of("src", "test", "resources", "class", "literals")
val tu =
TestUtils.analyzeAndGetFirstTU(
// We just need to specify one file to trigger the class byte loader
// We just need to specify one file to trigger the byte code loader
listOf(topLevel.resolve("mypackage/Literals.class").toFile()),
topLevel,
true
Expand All @@ -167,4 +168,56 @@ class JVMLanguageFrontendTest {

println(haveFun.code)
}

@Test
fun testFieldsClass() {
// This will be our classpath
val topLevel = Path.of("src", "test", "resources", "class", "fields")
val tu =
TestUtils.analyzeAndGetFirstTU(
// We just need to specify one file to trigger the byte code loader
listOf(topLevel.resolve("mypackage/Fields.class").toFile()),
topLevel,
true
) {
it.registerPass<EdgeCachePass>()
it.registerLanguage<JVMLanguage>()
}
assertNotNull(tu)

tu.methods.forEach { println(it.code) }

val refs = tu.refs.filterIsInstance<MemberExpression>()
refs.forEach {
val refersTo = it.refersTo
assertNotNull(refersTo, "${it.name} could not be resolved")
assertFalse(
refersTo.isInferred,
"${it.name} should not be resolved to an inferred node"
)
}
}

@Disabled
@Test
fun testLiteralsSource() {
// This will be our classpath
val topLevel = Path.of("src", "test", "resources", "class", "literals")
val tu =
TestUtils.analyzeAndGetFirstTU(
// We just need to specify one file to trigger the source code loader
listOf(topLevel.resolve("mypackage/Literals.java").toFile()),
topLevel,
true
) {
it.registerPass<EdgeCachePass>()
it.registerLanguage<JVMLanguage>()
}
assertNotNull(tu)

val haveFun = tu.methods["haveFunWithLiterals"]
assertNotNull(haveFun)

println(haveFun.code)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package mypackage;

public class Fields {

private int a = 2;

Fields() {
resetA();
}

public void setA(int a) {
this.a = a;
}

private void resetA() {
this.a = 10;
}
}
3 changes: 2 additions & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,14 @@ nexus-publish-gradle = { module = "io.github.gradle-nexus:publish-plugin", versi

sootup-core = { module = "com.github.oxisto.SootUp:sootup.core", version.ref = "sootup" }
sootup-java-core = { module = "com.github.oxisto.SootUp:sootup.java.core", version.ref = "sootup" }
sootup-java-sourcecode = { module = "com.github.oxisto.SootUp:sootup.java.sourcecode", version.ref = "sootup" }
sootup-java-bytecode = { module = "com.github.oxisto.SootUp:sootup.java.bytecode", version.ref = "sootup" }
sootup-jimple-parser = { module = "com.github.oxisto.SootUp:sootup.jimple.parser", version.ref = "sootup" }

[bundles]
log4j = ["log4j-impl", "log4j-core"]
neo4j = ["neo4j-ogm-core", "neo4j-ogm-bolt-driver"]
sootup = ["sootup-core", "sootup-java-core", "sootup-java-bytecode", "sootup-jimple-parser"]
sootup = ["sootup-core", "sootup-java-core", "sootup-java-sourcecode", "sootup-java-bytecode", "sootup-jimple-parser"]

[plugins]
kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin"}
Expand Down

0 comments on commit 6de25da

Please sign in to comment.