From 2526e6ae79a6e5639e38bf796fd9e8d59759234f Mon Sep 17 00:00:00 2001 From: "M.Schmidt" Date: Tue, 26 Nov 2024 10:51:31 +0100 Subject: [PATCH] sootup:tests unsound (possibly because of cha <-> spark callgraphalgo) --- .../test/java/test/FrameworkScopeFactory.java | 133 +++++++++++------- boomerangScope-SootUp/pom.xml | 50 +++++++ .../sootup/BoomerangPreInterceptor.java | 31 ++-- .../framework/sootup/JimpleUpStatement.java | 4 +- .../framework/sootup/SootUpCallGraph.java | 56 ++++---- .../sootup/SootUpDataFlowScopeUtil.java | 25 ++-- pom.xml | 45 +++++- 7 files changed, 230 insertions(+), 114 deletions(-) diff --git a/boomerangPDS/src/test/java/test/FrameworkScopeFactory.java b/boomerangPDS/src/test/java/test/FrameworkScopeFactory.java index e18a0991..8d3b4450 100644 --- a/boomerangPDS/src/test/java/test/FrameworkScopeFactory.java +++ b/boomerangPDS/src/test/java/test/FrameworkScopeFactory.java @@ -26,12 +26,12 @@ import sootup.core.model.SourceType; import sootup.core.signatures.MethodSignature; import sootup.core.transform.BodyInterceptor; -import sootup.java.bytecode.inputlocation.JavaClassPathAnalysisInputLocation; -import sootup.java.bytecode.inputlocation.JrtFileSystemAnalysisInputLocation; +import sootup.interceptors.BytecodeBodyInterceptors; +import sootup.java.bytecode.frontend.inputlocation.JavaClassPathAnalysisInputLocation; +import sootup.java.bytecode.frontend.inputlocation.JrtFileSystemAnalysisInputLocation; import sootup.java.core.JavaSootClass; -import sootup.java.core.JavaSootMethod; -import sootup.java.core.interceptors.BytecodeBodyInterceptors; import sootup.java.core.views.JavaView; +import sootup.jimple.frontend.JimpleStringAnalysisInputLocation; // TODO: refactor as parameterized test -> update to junit 5 public class FrameworkScopeFactory { @@ -156,25 +156,30 @@ private static FrameworkScope getSootFrameworkScope( } SootMethod methodByName = c.getMethodByName("main"); + eps.add(methodByName); + for (SootMethod m : sootTestCaseClass.getMethods()) { if (m.isStaticInitializer()) { eps.add(m); } } - // collect entrypoints - for (SootClass inner : Scene.v().getClasses()) { - classCount++; - if (inner.getName().contains(sootTestCaseClass.getName())) { - inner.setApplicationClass(); - for (SootMethod m : inner.getMethods()) { - if (m.isStaticInitializer()) { - eps.add(m); - } - } - } - } - eps.add(methodByName); + // TODO: check if the following block is needed / correct in this branch + /* + // collect entrypoints + for (SootClass inner : Scene.v().getClasses()) { + classCount++; + if (inner.getName().contains(sootTestCaseClass.getName())) { + inner.setApplicationClass(); + for (SootMethod m : inner.getMethods()) { + if (m.isStaticInitializer()) { + eps.add(m); + } + } + } + } + + */ if (eps.isEmpty()) { throw new IllegalStateException( @@ -240,7 +245,6 @@ private static String getTargetClass(SootMethod sootTestMethod, String testCaseC return sootClass.toString(); } - /** SootUp Framework setup TODO: [ms] refactor me! */ private static FrameworkScope getSootUpFrameworkScope( String pathStr, @@ -273,47 +277,70 @@ private static FrameworkScope getSootUpFrameworkScope( classPathInputLocation, includedPackages), new ScopedAnalysisInputLocation.DenylistingScopedAnalysisInputLocation( classPathInputLocation, excludedPackages))); - JavaView javaView = new JavaView(inputLocations); + JavaView javaView; sootup.callgraph.CallGraph cg; - List entypointSignatures; - List eps = Lists.newArrayList(); - - if (customEntrypointMethodName == null) { - // collect entrypoints - for (JavaSootClass sootClass : javaView.getClasses()) { - String scStr = sootClass.toString(); - if (scStr.equals(className) || (scStr.contains(className + "$"))) { - eps.addAll(sootClass.getMethods()); - } - } + List entypointSignatures = Lists.newArrayList(); - } else { - // build entrypoint - String jimpleClassStr = "class dummyClass\n" + - "{\n" + - " public static void main(java.lang.String[])\n" + - " {\n" + - " "+ className +" dummyObj;\n" + - " java.lang.String[] l0;\n" + - " l0 := @parameter0: java.lang.String[];\n" + - " dummyObj = new "+ className +";\n" + - " virtualinvoke dummyObj.<"+ className +": void "+customEntrypointMethodName+"()>();\n" + - " return;\n" + - " }\n" + - "}"; - - // new JimpleStringAnalysisInputLocation(jimpleClassStr) // currently in sootup:develop branch - - throw new UnsupportedOperationException("implement me!"); + if (customEntrypointMethodName == null) { + + javaView = new JavaView(inputLocations); + // collect entrypoints + for (JavaSootClass sootClass : javaView.getClasses().collect(Collectors.toList())) { + String scStr = sootClass.toString(); + if (scStr.equals(className) || (scStr.contains(className + "$"))) { + sootClass.getMethods().stream() + .map(SootClassMember::getSignature) + .forEach(entypointSignatures::add); + } } - // initialize CallGraphAlgorithm - entypointSignatures = - eps.stream().map(SootClassMember::getSignature).collect(Collectors.toList()); + } else { + + // build dummy entrypoint class + String jimpleClassStr = + "class dummyClass\n" + + "{\n" + + " public static void main(java.lang.String[])\n" + + " {\n" + + " " + + className + + " dummyObj;\n" + + " java.lang.String[] l0;\n" + + " l0 := @parameter0: java.lang.String[];\n" + + " dummyObj = new " + + className + + ";\n" + + " virtualinvoke dummyObj.<" + + className + + ": void " + + customEntrypointMethodName + + "()>();\n" + + " return;\n" + + " }\n" + + "}"; + + JimpleStringAnalysisInputLocation jimpleStringAnalysisInputLocation = + new JimpleStringAnalysisInputLocation( + jimpleClassStr); // currently in sootup:develop branch + inputLocations.add(jimpleStringAnalysisInputLocation); + javaView = new JavaView(inputLocations); + + MethodSignature dummyEntrypoint = + javaView + .getIdentifierFactory() + .parseMethodSignature(""); + assert javaView.getMethod(dummyEntrypoint).isPresent(); + + entypointSignatures.add(dummyEntrypoint); + } - // TODO: adapt if: --> use spark when available - CallGraphAlgorithm cga = customEntrypointMethodName == null? new ClassHierarchyAnalysisAlgorithm(javaView) : new ClassHierarchyAnalysisAlgorithm(javaView); + // initialize CallGraphAlgorithm + // TODO: use spark when available + CallGraphAlgorithm cga = + customEntrypointMethodName == null + ? new ClassHierarchyAnalysisAlgorithm(javaView) + : new ClassHierarchyAnalysisAlgorithm(javaView); cg = cga.initialize(entypointSignatures); return new SootUpFrameworkScope(javaView, cg, entypointSignatures); diff --git a/boomerangScope-SootUp/pom.xml b/boomerangScope-SootUp/pom.xml index 957cf51b..ec547cf8 100644 --- a/boomerangScope-SootUp/pom.xml +++ b/boomerangScope-SootUp/pom.xml @@ -23,6 +23,7 @@ de.fraunhofer.iem boomerangScope + + + + + com.github.soot-oss.SootUp + sootup.core + develop-SNAPSHOT + + + com.github.soot-oss.SootUp + sootup.java.core + develop-SNAPSHOT + + + com.github.soot-oss.SootUp + sootup.java.bytecode.frontend + develop-SNAPSHOT + + + com.github.soot-oss.SootUp + sootup.callgraph + develop-SNAPSHOT + + + com.github.soot-oss.SootUp + sootup.analysis.intraprocedural + develop-SNAPSHOT + + + com.github.soot-oss.SootUp + sootup.analysis.interprocedural + develop-SNAPSHOT + + + com.github.soot-oss.SootUp + sootup.interceptors + develop-SNAPSHOT + + + com.github.soot-oss.SootUp + sootup.jimple.frontend + develop-SNAPSHOT + + + + jitpack.io + https://jitpack.io + + \ No newline at end of file diff --git a/boomerangScope-SootUp/src/main/java/boomerang/framework/sootup/BoomerangPreInterceptor.java b/boomerangScope-SootUp/src/main/java/boomerang/framework/sootup/BoomerangPreInterceptor.java index 7e68c9ae..f2decb53 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/framework/sootup/BoomerangPreInterceptor.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/framework/sootup/BoomerangPreInterceptor.java @@ -20,12 +20,7 @@ import sootup.core.jimple.common.ref.JArrayRef; import sootup.core.jimple.common.ref.JInstanceFieldRef; import sootup.core.jimple.common.ref.JStaticFieldRef; -import sootup.core.jimple.common.stmt.JAssignStmt; -import sootup.core.jimple.common.stmt.JIfStmt; -import sootup.core.jimple.common.stmt.JInvokeStmt; -import sootup.core.jimple.common.stmt.JNopStmt; -import sootup.core.jimple.common.stmt.JReturnStmt; -import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.jimple.common.stmt.*; import sootup.core.model.Body; import sootup.core.transform.BodyInterceptor; import sootup.core.views.View; @@ -116,7 +111,7 @@ private void transformConstantsAtFieldWrites(Body.BodyBuilder body) { } } - if (stmt.containsInvokeExpr()) { + if (stmt.isInvokableStmt()) { /* Extract constant arguments to new assignments * - method(10) * becomes @@ -125,8 +120,11 @@ private void transformConstantsAtFieldWrites(Body.BodyBuilder body) { */ List newArgs = new ArrayList<>(); - for (int i = 0; i < stmt.getInvokeExpr().getArgCount(); i++) { - Immediate arg = stmt.getInvokeExpr().getArg(i); + InvokableStmt invStmt = stmt.asInvokableStmt(); + + AbstractInvokeExpr invokeExpr = invStmt.getInvokeExpr().get(); + for (int i = 0; i < invokeExpr.getArgCount(); i++) { + Immediate arg = invokeExpr.getArg(i); if (arg instanceof Constant && !(arg instanceof ClassConstant)) { String label = LABEL + replaceCounter++; @@ -145,18 +143,17 @@ private void transformConstantsAtFieldWrites(Body.BodyBuilder body) { // Update the invoke expression with new arguments // TODO: [ms] make use of new ReplaceUseExprVisitor() AbstractInvokeExpr newInvokeExpr; - if (stmt.getInvokeExpr() instanceof JStaticInvokeExpr) { - JStaticInvokeExpr staticInvokeExpr = (JStaticInvokeExpr) stmt.getInvokeExpr(); + if (invokeExpr instanceof JStaticInvokeExpr) { + JStaticInvokeExpr staticInvokeExpr = (JStaticInvokeExpr) invokeExpr; newInvokeExpr = staticInvokeExpr.withArgs(newArgs); - } else if (stmt.getInvokeExpr() instanceof AbstractInstanceInvokeExpr) { - AbstractInstanceInvokeExpr instanceInvokeExpr = - (AbstractInstanceInvokeExpr) stmt.getInvokeExpr(); + } else if (invokeExpr instanceof AbstractInstanceInvokeExpr) { + AbstractInstanceInvokeExpr instanceInvokeExpr = (AbstractInstanceInvokeExpr) invokeExpr; newInvokeExpr = instanceInvokeExpr.withArgs(newArgs); } else { // TODO Are there other relevant cases? - newInvokeExpr = stmt.getInvokeExpr(); + newInvokeExpr = invokeExpr; } if (stmt instanceof JInvokeStmt) { @@ -209,8 +206,8 @@ private Collection getStatementsWithConstants(Body.BodyBuilder body) { } // Consider arguments of invoke expressions - if (stmt.containsInvokeExpr()) { - for (Value arg : stmt.getInvokeExpr().getArgs()) { + if (stmt.isInvokableStmt()) { + for (Value arg : stmt.asInvokableStmt().getInvokeExpr().get().getArgs()) { if (arg instanceof Constant) { result.add(stmt); } diff --git a/boomerangScope-SootUp/src/main/java/boomerang/framework/sootup/JimpleUpStatement.java b/boomerangScope-SootUp/src/main/java/boomerang/framework/sootup/JimpleUpStatement.java index 71e621e8..cef3926e 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/framework/sootup/JimpleUpStatement.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/framework/sootup/JimpleUpStatement.java @@ -57,7 +57,7 @@ public boolean containsStaticFieldAccess() { @Override public boolean containsInvokeExpr() { - return delegate.containsInvokeExpr(); + return delegate.isInvokableStmt(); } @Override @@ -165,7 +165,7 @@ public boolean isPhiStatement() { public InvokeExpr getInvokeExpr() { assert containsInvokeExpr(); - return new JimpleUpInvokeExpr(delegate.getInvokeExpr(), method); + return new JimpleUpInvokeExpr(delegate.asInvokableStmt().getInvokeExpr().get(), method); } @Override diff --git a/boomerangScope-SootUp/src/main/java/boomerang/framework/sootup/SootUpCallGraph.java b/boomerangScope-SootUp/src/main/java/boomerang/framework/sootup/SootUpCallGraph.java index e1bddad8..42796700 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/framework/sootup/SootUpCallGraph.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/framework/sootup/SootUpCallGraph.java @@ -5,11 +5,8 @@ import boomerang.scene.Statement; import java.util.Collection; import java.util.Optional; -import org.apache.commons.lang3.tuple.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import sootup.analysis.interprocedural.icfg.CGEdgeUtil; -import sootup.analysis.interprocedural.icfg.CalleeMethodSignature; import sootup.core.signatures.MethodSignature; import sootup.java.core.JavaSootMethod; @@ -19,32 +16,33 @@ public class SootUpCallGraph extends CallGraph { public SootUpCallGraph(sootup.callgraph.CallGraph callGraph, Collection entryPoints) { - Collection> edges = - CGEdgeUtil.getCallEdges(SootUpFrameworkScope.getInstance().getView(), callGraph); - - for (Pair edge : edges) { - Optional sourceOpt = - SootUpFrameworkScope.getInstance().getSootMethod(edge.getLeft()); - Optional targetOpt = - SootUpFrameworkScope.getInstance().getSootMethod(edge.getRight().getMethodSignature()); - - if (sourceOpt.isEmpty() || targetOpt.isEmpty()) { - continue; - } - - JavaSootMethod sourceMethod = sourceOpt.get(); - JavaSootMethod targetMethod = targetOpt.get(); - if (!sourceMethod.hasBody() || !targetMethod.hasBody()) { - continue; - } - - Statement callSite = - JimpleUpStatement.create( - edge.getRight().getSourceStmt(), JimpleUpMethod.of(sourceMethod)); - this.addEdge(new Edge(callSite, JimpleUpMethod.of(targetMethod))); - - LOGGER.trace("Added edge {} -> {}", callSite, targetMethod); - } + // TODO: add a convenience method for this(edge collecting) to sootup + callGraph.getMethodSignatures().stream() + .flatMap((MethodSignature methodSignature) -> callGraph.callsTo(methodSignature).stream()) + .forEach( + call -> { + Optional sourceOpt = + SootUpFrameworkScope.getInstance().getSootMethod(call.getSourceMethodSignature()); + Optional targetOpt = + SootUpFrameworkScope.getInstance().getSootMethod(call.getTargetMethodSignature()); + + if (sourceOpt.isEmpty() || targetOpt.isEmpty()) { + return; + } + + JavaSootMethod sourceMethod = sourceOpt.get(); + JavaSootMethod targetMethod = targetOpt.get(); + if (!sourceMethod.hasBody() || !targetMethod.hasBody()) { + return; + } + + Statement callSite = + JimpleUpStatement.create( + call.getInvokableStmt(), JimpleUpMethod.of(sourceMethod)); + this.addEdge(new Edge(callSite, JimpleUpMethod.of(targetMethod))); + + LOGGER.trace("Added edge {} -> {}", callSite, targetMethod); + }); for (Method em : entryPoints) { this.addEntryPoint(em); diff --git a/boomerangScope-SootUp/src/main/java/boomerang/framework/sootup/SootUpDataFlowScopeUtil.java b/boomerangScope-SootUp/src/main/java/boomerang/framework/sootup/SootUpDataFlowScopeUtil.java index cb7b5ddd..8ee073b7 100644 --- a/boomerangScope-SootUp/src/main/java/boomerang/framework/sootup/SootUpDataFlowScopeUtil.java +++ b/boomerangScope-SootUp/src/main/java/boomerang/framework/sootup/SootUpDataFlowScopeUtil.java @@ -113,11 +113,13 @@ public MapFilter(JavaView view) { view.getTypeHierarchy().implementersOf(guavaMapType).forEach(excludes::add); } } - for (JavaSootClass c : view.getClasses()) { - if (c.hasOuterClass() && excludes.contains(c.getOuterClass().get())) { - excludes.add(guavaMapType); - } - } + view.getClasses() + .filter(c -> c.hasOuterClass() && excludes.contains(c.getOuterClass().get())) + .forEach( + c -> { + excludes.add(guavaMapType); + }); + if (excludes.isEmpty()) { LOGGER.debug("Excludes empty for {}", MAP); } @@ -137,11 +139,14 @@ public IterableFilter(JavaView view) { JavaClassType iterableClassType = view.getIdentifierFactory().getClassType(ITERABLE); view.getTypeHierarchy().implementersOf(iterableClassType).forEach(excludes::add); - for (JavaSootClass c : view.getClasses()) { - if (c.hasOuterClass() && excludes.contains(c.getOuterClass().get())) { - excludes.add(iterableClassType); - } - } + + view.getClasses() + .filter(c -> c.hasOuterClass() && excludes.contains(c.getOuterClass().get())) + .forEach( + c -> { + excludes.add(iterableClassType); + }); + if (excludes.isEmpty()) { LOGGER.debug("Excludes empty for {}", ITERABLE); } diff --git a/pom.xml b/pom.xml index 8c2e0253..6e269cd6 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 de.fraunhofer.iem SPDS @@ -19,7 +20,8 @@ scm:git:git@github.com:secure-software-engineering/SparseBoomerang.git - scm:git:ssh://github.com:secure-software-engineering/SparseBoomerang.git + scm:git:ssh://github.com:secure-software-engineering/SparseBoomerang.git + https://github.com/secure-software-engineering/SparseBoomerang @@ -213,6 +215,43 @@ boomerangScope ${project.version} + + + org.soot-oss + sootup.core + 1.3.0 + + + org.soot-oss + sootup.java.core + 1.3.0 + + + org.soot-oss + sootup.java.sourcecode + 1.3.0 + + + org.soot-oss + sootup.java.bytecode + 1.3.0 + + + org.soot-oss + sootup.jimple.parser + 1.3.0 + + + org.soot-oss + sootup.callgraph + 1.3.0 + + + org.soot-oss + sootup.analysis + 1.3.0 + + @@ -276,7 +315,7 @@ - + ci