Skip to content

Commit

Permalink
Adding support for backwards interprocedural CFG
Browse files Browse the repository at this point in the history
  • Loading branch information
shazib78 committed Sep 30, 2024
1 parent c5fd96c commit 33aa6a1
Show file tree
Hide file tree
Showing 2 changed files with 234 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -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<Stmt, SootMethod> {

protected final BiDiInterproceduralCFG<Stmt, SootMethod> delegate;

public BackwardsInterproceduralCFG(BiDiInterproceduralCFG<Stmt, SootMethod> fwICFG) {
delegate = fwICFG;
}

// swapped
@Override
public List<Stmt> getSuccsOf(Stmt n) {
return delegate.getPredsOf(n);
}

// swapped
@Override
public Collection<Stmt> getStartPointsOf(SootMethod m) {
return delegate.getEndPointsOf(m);
}

// swapped
@Override
public List<Stmt> 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<Stmt> allNonCallStartNodes() {
return delegate.allNonCallEndNodes();
}

// swapped
@Override
public List<Stmt> getPredsOf(Stmt u) {
return delegate.getSuccsOf(u);
}

// swapped
@Override
public Collection<Stmt> getEndPointsOf(SootMethod m) {
return delegate.getStartPointsOf(m);
}

// swapped
@Override
public List<Stmt> getPredsOfCallAt(Stmt u) {
return delegate.getSuccsOf(u);
}

// swapped
@Override
public Set<Stmt> allNonCallEndNodes() {
return delegate.allNonCallStartNodes();
}

// same
@Override
public SootMethod getMethodOf(Stmt n) {
return delegate.getMethodOf(n);
}

// same
@Override
public Collection<SootMethod> getCalleesOfCallAt(Stmt n) {
return delegate.getCalleesOfCallAt(n);
}

// same
@Override
public Collection<Stmt> getCallersOf(SootMethod m) {
return delegate.getCallersOf(m);
}

// same
@Override
public Set<Stmt> 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<Value> 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);
}
}
Original file line number Diff line number Diff line change
@@ -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<AnalysisInputLocation> 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<JavaSootMethod> methodOpt = view.getMethod(sig);
assertTrue(methodOpt.isPresent());
Collection<Stmt> callersOf = backwardsInterproceduralCFG.getCallersOf(methodOpt.get());
assertEquals(3, callersOf.size());
Set<MethodSignature> methodSignatures =
callersOf.stream()
.map(c -> c.asInvokableStmt().getInvokeExpr().get().getMethodSignature())
.collect(Collectors.toSet());
assertTrue(methodSignatures.contains(sig));
}
}

0 comments on commit 33aa6a1

Please sign in to comment.