-
-
Notifications
You must be signed in to change notification settings - Fork 83
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #976 from soot-oss/issue-965
implement call graph diff
- Loading branch information
Showing
7 changed files
with
249 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) { } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
132 changes: 132 additions & 0 deletions
132
sootup.callgraph/src/main/java/sootup/callgraph/CallGraphDifference.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
60 changes: 60 additions & 0 deletions
60
sootup.callgraph/src/test/java/sootup/callgraph/CallGraphDifferenceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters