Skip to content

Commit

Permalink
Merge pull request #976 from soot-oss/issue-965
Browse files Browse the repository at this point in the history
implement call graph diff
  • Loading branch information
swissiety authored Jul 19, 2024
2 parents a426cca + 2df6dec commit 0928c89
Show file tree
Hide file tree
Showing 7 changed files with 249 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*.class
!shared-test-resources/miniTestSuite/**/*.class
!sootup.analysis/src/test/resources/taint/binary/*.class
!sootup.callgraph/src/test/resources/callgraph/CallGraphDifference/binary/*.class

# Log file
*.log
Expand Down
35 changes: 35 additions & 0 deletions shared-test-resources/CallGraphDifference/Example.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
class Example {

public static void main(String[] args) {
A objB = new B();
B.staticDispatch(new C());

A objC=new E();

objB.virtualDispatch();
}
}

class A extends Object {
public void virtualDispatch() { }
public static void staticDispatch( Object o) { }
}

class B extends A {
public void virtualDispatch() { }
public static void staticDispatch( Object o) { }
}

class C extends D {
public static void staticDispatch( Object o) { }
}

class D extends A {
public void virtualDispatch() { }
public static void staticDispatch( Object o) { }
}

class E extends A {
public void virtualDispatch() { }
public static void staticDispatch( Object o) { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,11 @@ boolean containsCall(
*/
@Nonnull
MutableCallGraph copy();

/**
* This method compares the difference between the current call graph and call graph passed into
* the argument.
*/
@Nonnull
CallGraphDifference diff(@Nonnull CallGraph callGraph);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package sootup.callgraph;

import java.util.*;
import java.util.stream.Collectors;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.commons.lang3.tuple.Pair;
import sootup.core.signatures.MethodSignature;

/*-
* #%L
* Soot
* %%
* Copyright (C) 2024 Sahil Agichani
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 2.1 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/lgpl-2.1.html>.
* #L%
*/

public class CallGraphDifference {

private final CallGraph baseCallGraph;
private final CallGraph otherCallGraph;

private final List<Pair<MethodSignature, MethodSignature>> baseCallGraphEdges;
private final List<Pair<MethodSignature, MethodSignature>> otherCallGraphEdges;

public CallGraphDifference(CallGraph baseCallGraph, CallGraph otherCallGraph) {
this.baseCallGraph = baseCallGraph;
this.otherCallGraph = otherCallGraph;
this.baseCallGraphEdges = constructEdges(baseCallGraph);
this.otherCallGraphEdges = constructEdges(otherCallGraph);
}

private List<Pair<MethodSignature, MethodSignature>> constructEdges(CallGraph cg) {
List<Pair<MethodSignature, MethodSignature>> cgEdges = new ArrayList<>();
for (MethodSignature srcNode : cg.getMethodSignatures()) {
Set<MethodSignature> outNodes = cg.callsFrom(srcNode);
for (MethodSignature targetNode : outNodes) {
cgEdges.add(new MutablePair<>(srcNode, targetNode));
}
}
return cgEdges;
}

public CallGraph getBaseCallGraph() {
return baseCallGraph;
}

public CallGraph getOtherCallGraph() {
return otherCallGraph;
}

public List<Pair<MethodSignature, MethodSignature>> getBaseCallGraphEdges() {
return baseCallGraphEdges;
}

public List<Pair<MethodSignature, MethodSignature>> getOtherCallGraphEdges() {
return otherCallGraphEdges;
}

/*
In the intersectedCalls() function, we iterate over each edge in both call graphs and
return the intersection of the edges.
*/
public List<Pair<MethodSignature, MethodSignature>> intersectedCalls() {
return baseCallGraphEdges.stream()
.filter(otherCallGraphEdges::contains)
.collect(Collectors.toList());
}

/*
In the intersectedMethods() function, we iterate over each node in both call graphs and
return the intersection of the nodes.
*/
public List<MethodSignature> intersectedMethods() {
return baseCallGraph.getMethodSignatures().stream()
.filter(otherCallGraph.getMethodSignatures()::contains)
.collect(Collectors.toList());
}

/*
In the uniqueBaseGraphCalls() function, we iterate over each edges in base call graph and
return the unique edges present in the base call graph.
*/
public List<Pair<MethodSignature, MethodSignature>> uniqueBaseGraphCalls() {
return baseCallGraphEdges.stream()
.filter(edge -> !otherCallGraphEdges.contains(edge))
.collect(Collectors.toList());
}

/*
In the uniqueBaseGraphMethods() function, we iterate over each node in base call graph and
return the unique nodes present in the base call graph.
*/
public List<MethodSignature> uniqueBaseGraphMethods() {
return baseCallGraph.getMethodSignatures().stream()
.filter(node -> !otherCallGraph.getMethodSignatures().contains(node))
.collect(Collectors.toList());
}

/*
In the uniqueOtherGraphCalls() function, we iterate over each edges in other call graph and
return the unique edges present in the other call graph.
*/
public List<Pair<MethodSignature, MethodSignature>> uniqueOtherGraphCalls() {
return otherCallGraphEdges.stream()
.filter(edge -> !baseCallGraphEdges.contains(edge))
.collect(Collectors.toList());
}

/*
In the uniqueOtherGraphMethods() function, we iterate over each node in other call graph and
return the unique nodes present in the other call graph.
*/
public List<MethodSignature> uniqueOtherGraphMethods() {
return otherCallGraph.getMethodSignatures().stream()
.filter(node -> !baseCallGraph.getMethodSignatures().contains(node))
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,12 @@ public MutableCallGraph copy() {
(DefaultDirectedGraph<Vertex, Edge>) graph.clone(), new HashMap<>(signatureToVertex));
}

@Nonnull
@Override
public CallGraphDifference diff(@Nonnull CallGraph callGraph) {
return new CallGraphDifference(this, callGraph);
}

/**
* it returns the vertex of the graph that describes the given method signature in the call graph.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package sootup.callgraph;

import java.util.Collections;
import java.util.List;
import org.apache.commons.lang3.tuple.Pair;
import org.junit.jupiter.api.Test;
import sootup.core.inputlocation.AnalysisInputLocation;
import sootup.core.model.SourceType;
import sootup.core.signatures.MethodSignature;
import sootup.java.bytecode.inputlocation.JavaClassPathAnalysisInputLocation;
import sootup.java.core.types.JavaClassType;
import sootup.java.core.views.JavaView;

public class CallGraphDifferenceTest {

@Test
public void testCGDiff() {
String baseDir = "../shared-test-resources/CallGraphDifference/binary/";
AnalysisInputLocation inputLocation =
new JavaClassPathAnalysisInputLocation(
baseDir, SourceType.Application, Collections.emptyList());
JavaView view = new JavaView(inputLocation);

ClassHierarchyAnalysisAlgorithm chaAlgorithm = new ClassHierarchyAnalysisAlgorithm(view);
JavaClassType chaClassType = view.getIdentifierFactory().getClassType("Example");
MethodSignature chaMethodSignature =
view.getIdentifierFactory()
.getMethodSignature(
chaClassType, "main", "void", Collections.singletonList("java.lang.String[]"));
CallGraph cg1 = chaAlgorithm.initialize(Collections.singletonList(chaMethodSignature));

RapidTypeAnalysisAlgorithm rtaAlgorithm = new RapidTypeAnalysisAlgorithm(view);
CallGraph cg2 = rtaAlgorithm.initialize(Collections.singletonList(chaMethodSignature));

CallGraphDifference callGraphDifference = cg1.diff(cg2);
System.out.println("Unique Base Graph Calls/Edges");
List<Pair<MethodSignature, MethodSignature>> uniqueBaseGraphCalls =
callGraphDifference.uniqueBaseGraphCalls();
uniqueBaseGraphCalls.forEach(System.out::println);
System.out.println("Unique Base Graph Methods/Nodes");
List<MethodSignature> uniqueBaseGraphMethods = callGraphDifference.uniqueBaseGraphMethods();
uniqueBaseGraphMethods.forEach(System.out::println);

System.out.println("Unique Other Graph Calls/Edges");
List<Pair<MethodSignature, MethodSignature>> uniqueOtherGraphCalls =
callGraphDifference.uniqueOtherGraphCalls();
uniqueOtherGraphCalls.forEach(System.out::println);
System.out.println("Unique Other Graph Methods/Nodes");
List<MethodSignature> uniqueOtherGraphMethods = callGraphDifference.uniqueOtherGraphMethods();
uniqueOtherGraphMethods.forEach(System.out::println);

System.out.println("Intersected Calls/Edges");
List<Pair<MethodSignature, MethodSignature>> intersectedCalls =
callGraphDifference.intersectedCalls();
intersectedCalls.forEach(System.out::println);
System.out.println("Intersected Methods/Nodes");
List<MethodSignature> intersectedMethods = callGraphDifference.intersectedMethods();
intersectedMethods.forEach(System.out::println);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
import qilin.util.DataFactory;
import qilin.util.queue.ChunkedQueue;
import qilin.util.queue.QueueReader;
import sootup.callgraph.CallGraph;
import sootup.callgraph.CallGraphDifference;
import sootup.callgraph.MutableCallGraph;
import sootup.core.jimple.common.stmt.Stmt;
import sootup.core.model.SootMethod;
Expand Down Expand Up @@ -450,6 +452,12 @@ public MutableCallGraph copy() {
throw new UnsupportedOperationException();
}

@Nonnull
@Override
public CallGraphDifference diff(@Nonnull CallGraph callGraph) {
throw new UnsupportedOperationException();
}

@Override
public boolean containsMethod(@Nonnull MethodSignature method) {
return this.methods.contains(method);
Expand Down

0 comments on commit 0928c89

Please sign in to comment.