From 33aa6a191934efb72c7b381bfd1f71a8d6725d7a Mon Sep 17 00:00:00 2001 From: shazib78 <85836234+shazib78@users.noreply.github.com> Date: Mon, 30 Sep 2024 21:12:43 +0200 Subject: [PATCH] Adding support for backwards interprocedural CFG --- .../icfg/BackwardsInterproceduralCFG.java | 151 ++++++++++++++++++ .../icfg/BackwardsInterproceduralCFGTest.java | 83 ++++++++++ 2 files changed, 234 insertions(+) create mode 100644 sootup.analysis.interprocedural/src/main/java/sootup/analysis/interprocedural/icfg/BackwardsInterproceduralCFG.java create mode 100644 sootup.analysis.interprocedural/src/test/java/sootup/analysis/interprocedural/icfg/BackwardsInterproceduralCFGTest.java diff --git a/sootup.analysis.interprocedural/src/main/java/sootup/analysis/interprocedural/icfg/BackwardsInterproceduralCFG.java b/sootup.analysis.interprocedural/src/main/java/sootup/analysis/interprocedural/icfg/BackwardsInterproceduralCFG.java new file mode 100644 index 00000000000..9e66b125122 --- /dev/null +++ b/sootup.analysis.interprocedural/src/main/java/sootup/analysis/interprocedural/icfg/BackwardsInterproceduralCFG.java @@ -0,0 +1,151 @@ +package sootup.analysis.interprocedural.icfg; + +import java.util.Collection; +import java.util.List; +import java.util.Set; +import sootup.core.graph.StmtGraph; +import sootup.core.jimple.basic.Value; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootMethod; + +/** + * Same as {@link JimpleBasedInterproceduralCFG} but based on inverted Stmt graphs. This should be + * used for backward analyses. + */ +public class BackwardsInterproceduralCFG implements BiDiInterproceduralCFG { + + protected final BiDiInterproceduralCFG delegate; + + public BackwardsInterproceduralCFG(BiDiInterproceduralCFG fwICFG) { + delegate = fwICFG; + } + + // swapped + @Override + public List getSuccsOf(Stmt n) { + return delegate.getPredsOf(n); + } + + // swapped + @Override + public Collection getStartPointsOf(SootMethod m) { + return delegate.getEndPointsOf(m); + } + + // swapped + @Override + public List getReturnSitesOfCallAt(Stmt n) { + return delegate.getPredsOfCallAt(n); + } + + // swapped + @Override + public boolean isExitStmt(Stmt stmt) { + return delegate.isStartPoint(stmt); + } + + // swapped + @Override + public boolean isStartPoint(Stmt stmt) { + return delegate.isExitStmt(stmt); + } + + // swapped + @Override + public Set allNonCallStartNodes() { + return delegate.allNonCallEndNodes(); + } + + // swapped + @Override + public List getPredsOf(Stmt u) { + return delegate.getSuccsOf(u); + } + + // swapped + @Override + public Collection getEndPointsOf(SootMethod m) { + return delegate.getStartPointsOf(m); + } + + // swapped + @Override + public List getPredsOfCallAt(Stmt u) { + return delegate.getSuccsOf(u); + } + + // swapped + @Override + public Set allNonCallEndNodes() { + return delegate.allNonCallStartNodes(); + } + + // same + @Override + public SootMethod getMethodOf(Stmt n) { + return delegate.getMethodOf(n); + } + + // same + @Override + public Collection getCalleesOfCallAt(Stmt n) { + return delegate.getCalleesOfCallAt(n); + } + + // same + @Override + public Collection getCallersOf(SootMethod m) { + return delegate.getCallersOf(m); + } + + // same + @Override + public Set getCallsFromWithin(SootMethod m) { + return delegate.getCallsFromWithin(m); + } + + // same + @Override + public boolean isCallStmt(Stmt stmt) { + return delegate.isCallStmt(stmt); + } + + // same + @Override + public StmtGraph getOrCreateStmtGraph(SootMethod m) { + return delegate.getOrCreateStmtGraph(m); + } + + // same + @Override + public List getParameterRefs(SootMethod m) { + return delegate.getParameterRefs(m); + } + + @Override + public boolean isFallThroughSuccessor(Stmt stmt, Stmt succ) { + throw new UnsupportedOperationException("not implemented because semantics unclear"); + } + + @Override + public boolean isBranchTarget(Stmt stmt, Stmt succ) { + throw new UnsupportedOperationException("not implemented because semantics unclear"); + } + + // swapped + @Override + public boolean isReturnSite(Stmt n) { + for (Stmt pred : getSuccsOf(n)) { + if (isCallStmt(pred)) { + return true; + } + } + return false; + } + + // same + @Override + public boolean isReachable(Stmt u) { + return delegate.isReachable(u); + } +} diff --git a/sootup.analysis.interprocedural/src/test/java/sootup/analysis/interprocedural/icfg/BackwardsInterproceduralCFGTest.java b/sootup.analysis.interprocedural/src/test/java/sootup/analysis/interprocedural/icfg/BackwardsInterproceduralCFGTest.java new file mode 100644 index 00000000000..616c8c0fb8d --- /dev/null +++ b/sootup.analysis.interprocedural/src/test/java/sootup/analysis/interprocedural/icfg/BackwardsInterproceduralCFGTest.java @@ -0,0 +1,83 @@ +package sootup.analysis.interprocedural.icfg; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.*; +import java.util.stream.Collectors; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import sootup.core.inputlocation.AnalysisInputLocation; +import sootup.core.jimple.common.stmt.Stmt; +import sootup.core.model.SootClass; +import sootup.core.model.SootMethod; +import sootup.core.signatures.MethodSignature; +import sootup.java.bytecode.frontend.inputlocation.JavaClassPathAnalysisInputLocation; +import sootup.java.core.JavaIdentifierFactory; +import sootup.java.core.JavaSootMethod; +import sootup.java.core.types.JavaClassType; +import sootup.java.core.views.JavaView; + +@Tag("Java8") +class BackwardsInterproceduralCFGTest { + protected static JavaView view; + protected static MethodSignature entryMethodSignature; + protected static SootMethod entryMethod; + + @BeforeAll + public static void setup() { + List inputLocations = new ArrayList<>(); + inputLocations.add(new JavaClassPathAnalysisInputLocation("src/test/resources/icfg/binary")); + view = new JavaView(inputLocations); + JavaIdentifierFactory identifierFactory = JavaIdentifierFactory.getInstance(); + JavaClassType mainClassSignature = + identifierFactory.getClassType("ICFGExampleForInvokableStmt"); + SootClass sc = view.getClass(mainClassSignature).get(); + entryMethod = + sc.getMethods().stream().filter(e -> e.getName().equals("entryPoint")).findFirst().get(); + entryMethodSignature = entryMethod.getSignature(); + } + + @Test + void methodStartAndEndPointTest() { + JimpleBasedInterproceduralCFG forwardICFG = + new JimpleBasedInterproceduralCFG(view, entryMethodSignature, false, false); + + BackwardsInterproceduralCFG backwardsInterproceduralCFG = + new BackwardsInterproceduralCFG(forwardICFG); + + assertEquals( + forwardICFG.getStartPointsOf(entryMethod), + backwardsInterproceduralCFG.getEndPointsOf(entryMethod)); + assertEquals( + forwardICFG.getEndPointsOf(entryMethod), + backwardsInterproceduralCFG.getStartPointsOf(entryMethod)); + } + + @Test + void methodToCallerStmtTest() { + JimpleBasedInterproceduralCFG forwardICFG = + new JimpleBasedInterproceduralCFG(view, entryMethodSignature, false, false); + + BackwardsInterproceduralCFG backwardsInterproceduralCFG = + new BackwardsInterproceduralCFG(forwardICFG); + + MethodSignature sig = + JavaIdentifierFactory.getInstance() + .getMethodSignature( + "ICFGExampleForInvokableStmt", + "foo", + "void", + Collections.singletonList("java.lang.String")); + Optional methodOpt = view.getMethod(sig); + assertTrue(methodOpt.isPresent()); + Collection callersOf = backwardsInterproceduralCFG.getCallersOf(methodOpt.get()); + assertEquals(3, callersOf.size()); + Set methodSignatures = + callersOf.stream() + .map(c -> c.asInvokableStmt().getInvokeExpr().get().getMethodSignature()) + .collect(Collectors.toSet()); + assertTrue(methodSignatures.contains(sig)); + } +}