Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

open up the api to easier adapt the current call graph algorithm or… #633

Merged
merged 6 commits into from
Jun 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,9 @@
import sootup.java.core.types.JavaClassType;

/**
* The AbstractCallGraphAlgorithm class is the super class of all call graph algorithmen. It
* provides basic methods used in all call graph algorithm. It is abstract since it has no
* implemented functionality to resolve method calls because it is decided by the applied call graph
* algorithm
* The AbstractCallGraphAlgorithm class is the super class of all call graph algorithm. It provides
* basic methods used in all call graph algorithm. It is abstract since it has no implemented
* functionality to resolve method calls because it is decided by the applied call graph algorithm
*/
public abstract class AbstractCallGraphAlgorithm implements CallGraphAlgorithm {

Expand All @@ -73,36 +72,60 @@ protected AbstractCallGraphAlgorithm(@Nonnull View<? extends SootClass<?>> view)
@Nonnull
final CallGraph constructCompleteCallGraph(
View<? extends SootClass<?>> view, List<MethodSignature> entryPoints) {
MutableCallGraph cg = new GraphBasedCallGraph();
MutableCallGraph cg = initializeCallGraph();

Deque<MethodSignature> workList = new ArrayDeque<>(entryPoints);
Set<MethodSignature> processed = new HashSet<>();

// implicit edge from entry point to clinit
// implicit edge from entry point to static initializer
addImplicitEdgesOfEntryPoints(entryPoints, cg, workList);

processWorkList(view, workList, processed, cg);
return cg;
}

/**
* This method creates the mutable call graph which is used in the call graph algorithm. Overwrite
* it to change the used mutable call graph
*
* @return the initialized call graph used in the call graph algorithm
*/
protected MutableCallGraph initializeCallGraph() {
return new GraphBasedCallGraph();
}

/**
* This method adds implicit edges of the entry points of the call graph algorithm. It will add an
* edge to all static initializer of the entry points.
*
* @param entryPoints the entry points of the call graph algorithm
* @param cg the call graph which will save the added implicit edges.
* @param workList the implicit targets will be added to the work list to process in the call
* graph algorithm
*/
protected void addImplicitEdgesOfEntryPoints(
List<MethodSignature> entryPoints, MutableCallGraph cg, Deque<MethodSignature> workList) {
entryPoints.forEach(
methodSignature -> {
SootMethod clintMethod =
view.getMethod(methodSignature.getDeclClassType().getStaticInitializer())
.orElse(null);
if (clintMethod == null) return;
MethodSignature clinitSig = clintMethod.getSignature();
MethodSignature staticInitSig = clintMethod.getSignature();
if (!cg.containsMethod(methodSignature)) cg.addMethod(methodSignature);
if (!cg.containsMethod(clinitSig)) cg.addMethod(clinitSig);
if (!cg.containsCall(methodSignature, clinitSig)) {
cg.addCall(methodSignature, clinitSig);
workList.push(clinitSig);
if (!cg.containsMethod(staticInitSig)) cg.addMethod(staticInitSig);
if (!cg.containsCall(methodSignature, staticInitSig)) {
cg.addCall(methodSignature, staticInitSig);
workList.push(staticInitSig);
}
});

processWorkList(view, workList, processed, cg);
return cg;
}

/**
* Processes all entries in the <code>workList</code>, skipping those present in <code>processed
* </code>, adding call edges to the graph. Newly discovered methods are added to the <code>
* workList</code> and processed as well. <code>cg</code> is updated accordingly. The method
* postProcessingMethod is called after a method is processed in the <code>worklist</code>.
* postProcessingMethod is called after a method is processed in the <code>workList</code>.
*
* @param view it contains the classes.
* @param workList it contains all method that have to be processed in the call graph generation.
Expand Down Expand Up @@ -184,7 +207,7 @@ Stream<MethodSignature> resolveAllCallsFromSourceMethod(SootMethod sourceMethod)
* @return a stream containing all method signatures of targets of implicit calls.
*/
@Nonnull
Stream<MethodSignature> resolveAllImplicitCallsFromSourceMethod(
protected Stream<MethodSignature> resolveAllImplicitCallsFromSourceMethod(
View<? extends SootClass<?>> view, SootMethod sourceMethod) {
if (sourceMethod == null || !sourceMethod.hasBody()) return Stream.empty();

Expand All @@ -195,14 +218,14 @@ Stream<MethodSignature> resolveAllImplicitCallsFromSourceMethod(
}

/**
* It resolves all clinit calls caused by the given source method
* It resolves all static initializer calls caused by the given source method
*
* @param view it contains the class data
* @param sourceMethod the inspected source method
* @return a stream containing all method signatures of targets of implicit calls.
*/
@Nonnull
Stream<MethodSignature> resolveAllStaticInitializerCallsFromSourceMethod(
protected Stream<MethodSignature> resolveAllStaticInitializerCallsFromSourceMethod(
View<? extends SootClass<?>> view, SootMethod sourceMethod) {
if (sourceMethod == null || !sourceMethod.hasBody()) return Stream.empty();

Expand Down Expand Up @@ -259,9 +282,9 @@ Stream<MethodSignature> resolveAllStaticInitializerCallsFromSourceMethod(
* @param view it contains all classes
* @param sig the signature of the searched method
* @param <T> the generic type of the searched method object
* @return the found method object, or null if the metod was not found.
* @return the found method object, or null if the method was not found.
*/
final <T extends Method> T findMethodInHierarchy(
protected final <T extends Method> T findMethodInHierarchy(
@Nonnull View<? extends SootClass<?>> view, @Nonnull MethodSignature sig) {
Optional<? extends SootClass<?>> optSc = view.getClass(sig.getDeclClassType());

Expand Down Expand Up @@ -299,10 +322,10 @@ final <T extends Method> T findMethodInHierarchy(
*
* @param view view
* @param sourceMethod the processed method
* @param workList the current worklist that might be extended
* @param workList the current work list that might be extended
* @param cg the current cg that might be extended
*/
public abstract void preProcessingMethod(
protected abstract void preProcessingMethod(
View<? extends SootClass<?>> view,
MethodSignature sourceMethod,
@Nonnull Deque<MethodSignature> workList,
Expand All @@ -313,10 +336,10 @@ public abstract void preProcessingMethod(
*
* @param view it contains classes and the type hierarchy.
* @param sourceMethod the processed method
* @param workList the current worklist that might be extended
* @param workList the current work list that might be extended
* @param cg the current cg that might be extended
*/
public abstract void postProcessingMethod(
protected abstract void postProcessingMethod(
View<? extends SootClass<?>> view,
MethodSignature sourceMethod,
@Nonnull Deque<MethodSignature> workList,
Expand Down Expand Up @@ -422,7 +445,7 @@ public MethodSignature findMainMethod() {
}

/**
* This methods resolves the possible targets of a given invoke expression. The results are
* This method resolves the possible targets of a given invoke expression. The results are
* dependable of the applied call graph algorithm. therefore, it is abstract.
*
* @param method the method object that contains the given invoke expression in the body.
Expand All @@ -431,5 +454,6 @@ public MethodSignature findMainMethod() {
* algorithm.
*/
@Nonnull
abstract Stream<MethodSignature> resolveCall(SootMethod method, AbstractInvokeExpr invokeExpr);
protected abstract Stream<MethodSignature> resolveCall(
SootMethod method, AbstractInvokeExpr invokeExpr);
}
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ private Stream<MethodSignature> resolveAllSubClassCallTargets(
}

@Override
public void postProcessingMethod(
protected void postProcessingMethod(
View<? extends SootClass<?>> view,
MethodSignature sourceMethod,
@Nonnull Deque<MethodSignature> workList,
Expand All @@ -126,7 +126,7 @@ public void postProcessingMethod(
}

@Override
public void preProcessingMethod(
protected void preProcessingMethod(
View<? extends SootClass<?>> view,
MethodSignature sourceMethod,
@Nonnull Deque<MethodSignature> workList,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,58 +32,66 @@
import org.jgrapht.graph.DefaultDirectedGraph;
import sootup.core.signatures.MethodSignature;
import sootup.core.signatures.SootClassMemberSignature;
import sootup.java.core.types.JavaClassType;

/** This class implements a mutable call graph as a graph. */
public final class GraphBasedCallGraph implements MutableCallGraph {
public class GraphBasedCallGraph implements MutableCallGraph {

/**
* This internal class is used to describe a vertex in the graph. The vertex is defined by a
* method signature that describes the method.
*/
private static class Vertex {
protected static class Vertex {
@Nonnull final MethodSignature methodSignature;

private Vertex(@Nonnull MethodSignature methodSignature) {
protected Vertex(@Nonnull MethodSignature methodSignature) {
this.methodSignature = methodSignature;
}

@Nonnull
protected MethodSignature getMethodSignature() {
return methodSignature;
}
}

/** This internal class is used to describe the edge in the graph. */
private static class Edge {}
protected static class Edge {}

@Nonnull private final DefaultDirectedGraph<Vertex, Edge> graph;
@Nonnull private final Map<MethodSignature, Vertex> signatureToVertex;
// TODO: [ms] typeToVertices is not used in a useful way, yet?
@Nonnull private final Map<JavaClassType, Set<Vertex>> typeToVertices;

/** The constructor of the graph based call graph. it initializes the call graph object. */
GraphBasedCallGraph() {
public GraphBasedCallGraph() {
graph = new DefaultDirectedGraph<>(null, null, false);
signatureToVertex = new HashMap<>();
typeToVertices = new HashMap<>();
}

private GraphBasedCallGraph(
public GraphBasedCallGraph(
@Nonnull DefaultDirectedGraph<Vertex, Edge> graph,
@Nonnull Map<MethodSignature, Vertex> signatureToVertex,
@Nonnull Map<JavaClassType, Set<Vertex>> typeToVertices) {
@Nonnull Map<MethodSignature, Vertex> signatureToVertex) {
this.graph = graph;
this.signatureToVertex = signatureToVertex;
this.typeToVertices = typeToVertices;
}

@Override
public void addMethod(@Nonnull MethodSignature calledMethod) {
Vertex v = new Vertex(calledMethod);
graph.addVertex(v);
signatureToVertex.put(calledMethod, v);
addMethod(calledMethod, v);
}

protected void addMethod(@Nonnull MethodSignature calledMethod, Vertex vertex) {
graph.addVertex(vertex);
signatureToVertex.put(calledMethod, vertex);
}

@Override
public void addCall(
@Nonnull MethodSignature sourceMethod, @Nonnull MethodSignature targetMethod) {
graph.addEdge(vertexOf(sourceMethod), vertexOf(targetMethod), new Edge());
addCall(sourceMethod, targetMethod, new Edge());
}

protected void addCall(
@Nonnull MethodSignature sourceMethod, @Nonnull MethodSignature targetMethod, Edge edge) {
graph.addEdge(vertexOf(sourceMethod), vertexOf(targetMethod), edge);
}

@Nonnull
Expand Down Expand Up @@ -187,9 +195,7 @@ public String exportAsDot() {
@Override
public MutableCallGraph copy() {
return new GraphBasedCallGraph(
(DefaultDirectedGraph<Vertex, Edge>) graph.clone(),
new HashMap<>(signatureToVertex),
new HashMap<>(typeToVertices));
(DefaultDirectedGraph<Vertex, Edge>) graph.clone(), new HashMap<>(signatureToVertex));
}

/**
Expand All @@ -199,12 +205,27 @@ public MutableCallGraph copy() {
* @return the vertex of the requested method signature.
*/
@Nonnull
private Vertex vertexOf(@Nonnull MethodSignature method) {
protected Vertex vertexOf(@Nonnull MethodSignature method) {
Vertex methodVertex = signatureToVertex.get(method);
Preconditions.checkNotNull(methodVertex, "Node for " + method + " has not been added yet");
return methodVertex;
}

@Nonnull
protected DefaultDirectedGraph<Vertex, Edge> getGraph() {
return graph;
}

@Nonnull
protected Map<MethodSignature, Vertex> getSignatureToVertex() {
return signatureToVertex;
}

@Nonnull
protected MethodSignature vertex2MethodSignature(@Nonnull Vertex vertex) {
return vertex.getMethodSignature();
}

/**
* This method exports the call graph in a human-readable string. The String lists all nodes in
* the call graph. For each node it also lists the outgoing and incoming edges. An outgoing edge
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public CallGraph initialize(@Nonnull List<MethodSignature> entryPoints) {
*
* @param method this object contains the method body which is inspected.
*/
private void collectInstantiatedClassesInMethod(SootMethod method) {
protected void collectInstantiatedClassesInMethod(SootMethod method) {
if (method == null || method.isAbstract() || method.isNative()) {
return;
}
Expand Down Expand Up @@ -191,18 +191,18 @@ protected Stream<MethodSignature> resolveCall(SootMethod method, AbstractInvokeE
}

/**
* Pre-processing of a method in the RTA call graph algorithm
* Preprocessing of a method in the RTA call graph algorithm
*
* <p>Before processing the method, all instantiated types are collected inside the body of the
* sourceMethod.
*
* @param view view
* @param sourceMethod the processed method
* @param workList the current worklist
* @param workList the current work list
* @param cg the current cg
*/
@Override
public void preProcessingMethod(
protected void preProcessingMethod(
View<? extends SootClass<?>> view,
MethodSignature sourceMethod,
@Nonnull Deque<MethodSignature> workList,
Expand All @@ -217,7 +217,7 @@ public void preProcessingMethod(
}

/**
* Post processing of a method in the RTA call graph algorithm
* Postprocessing of a method in the RTA call graph algorithm
*
* <p>RTA has to add previously ignored calls because a found instantiation of a class could
* enable a call to a ignored method at a later time.
Expand All @@ -228,7 +228,7 @@ public void preProcessingMethod(
* @param cg the current cg is extended by new call targets and calls
*/
@Override
public void postProcessingMethod(
protected void postProcessingMethod(
View<? extends SootClass<?>> view,
MethodSignature sourceMethod,
@Nonnull Deque<MethodSignature> workList,
Expand Down