Skip to content
Open
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
2 changes: 1 addition & 1 deletion py-visualise/out/diff.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion py-visualise/testclasses/TestAdder2.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public int complexCalculation(int num1, int num2) {
if (result % 2 == 0) {
result /= 2;
} else {
result *= 3;
result += 3;
}
}

Expand Down
42 changes: 41 additions & 1 deletion src/main/java/org/pdgdiff/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.pdgdiff.graph.GraphExporter;
import org.pdgdiff.graph.GraphGenerator;
import org.pdgdiff.graph.GraphTraversal;
import org.pdgdiff.graph.PDG;
import org.pdgdiff.matching.GraphMatcherFactory;
import org.pdgdiff.matching.PDGComparator;
Expand All @@ -10,9 +11,11 @@
import soot.SootClass;
import soot.SootMethod;
import soot.toolkits.graph.pdg.HashMutablePDG;
import soot.toolkits.graph.pdg.PDGNode;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

public class Main {

Expand Down Expand Up @@ -70,10 +73,47 @@ private static List<PDG> generatePDGsForClass(SootClass sootClass) {
try {
// Retrieve the active body and generate the PDG
method.retrieveActiveBody();
System.out.println("Successfully retrieved active body for: " + method.getName() + " in " + sootClass.getName());
System.out.println("\n\nSuccessfully retrieved active body for: " + method.getName() + " in " + sootClass.getName());

// print jimple body
System.out.println("Jimple body for function" + method.getName());
System.out.println(method.getActiveBody().toString());

// Generate the PDG for the method
PDG pdg = GraphGenerator.constructPdg(sootClass, method);

List<Set<PDGNode>> connectedComponents = pdg.getConnectedComponents();
int numComponents = connectedComponents.size();
System.out.println("Number of connected components in method " + method.getName() + ": " + numComponents);
int componentIndex = 1;
for (Set<PDGNode> component : connectedComponents) {
System.out.println(" Component " + componentIndex + " size: " + component.size());
componentIndex++;
}
List<PDGNode> isolatedNodes = pdg.getIsolatedNodes();
if (!isolatedNodes.isEmpty()) {
System.out.println("Isolated nodes in method " + method.getName() + ":");
for (PDGNode node : isolatedNodes) {
System.out.println(" " + node);
}
} else {
System.out.println("No isolated nodes in method " + method.getName());
}

connectedComponents.sort((c1, c2) -> Integer.compare(c2.size(), c1.size()));
Set<PDGNode> largestComponent = connectedComponents.get(0);
System.out.println("Largest component size: " + largestComponent.size());

//
// List<PDGNode> eg = GraphTraversal.collectNodesBFS(pdg);
// List<PDGNode> eg2 = pdg.getNodes();
// // find differences
// System.out.println("\npdg: Checking differences between entire graph and connected component for method " + pdg.getCFG().getBody().getMethod().getSignature() + ". BFS:" + eg.size() + "entire:" + eg2.size() );
// for (PDGNode pdgNode : eg2) {
// if (!eg.contains(pdgNode)) {
// System.out.println("Node not found in BFS: " + pdgNode);
// }
// }
if (pdg != null) {
pdgList.add(pdg);
System.out.println("PDG generated for method: " + method.getName());
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/pdgdiff/graph/CycleDetection.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public static boolean hasCycle(PDG pdg) {
stack.clear();
stronglyConnectedComponents.clear();

List<PDGNode> allNodes = GraphTraversal.collectNodesBFS(pdg);
List<PDGNode> allNodes = new ArrayList<>(pdg.getNodes());

// Tarjan's algorithm starting from each node
for (PDGNode node : allNodes) {
Expand Down
15 changes: 14 additions & 1 deletion src/main/java/org/pdgdiff/graph/GraphGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import soot.toolkits.scalar.SimpleLocalUses;
import soot.toolkits.scalar.UnitValueBoxPair;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -47,7 +48,7 @@ public static HashMutablePDG generatePDG(SootClass sootClass, SootMethod method)

public static PDG constructPdg(SootClass sootClass, SootMethod method) {
Body body = method.retrieveActiveBody();
System.out.println("Generating PDG for method: " + method.getName());
System.out.println("\n\nGenerating PDG for method: " + method.getName());
UnitGraph eug = new ExceptionalUnitGraph(body);

//soot's api for creating postdominator tree
Expand All @@ -62,6 +63,7 @@ public static PDG constructPdg(SootClass sootClass, SootMethod method) {
SimpleLocalUses uses = new SimpleLocalUses(body, definitions);

Map<Unit, PDGNode> unitToNodeMap = new HashMap<>();
List<PDGNode> orderedNodes = new ArrayList<>();

// retrieve the start node of the PDG, which is the entry node of the CFG
// List<Unit> heads = eug.getHeads();
Expand All @@ -87,7 +89,9 @@ public static PDG constructPdg(SootClass sootClass, SootMethod method) {


for (Unit unit : body.getUnits()) {
boolean connected = false;
PDGNode node = addOrGetNode(pdg, unit, unitToNodeMap);
orderedNodes.add(node);

//add control dependencies based on dominance frontier
for (DominatorNode<Unit> dode : dominanceFrontier.getDominanceFrontierOf(postdominatorTree.getDode(unit))) {
Expand All @@ -101,7 +105,9 @@ public static PDG constructPdg(SootClass sootClass, SootMethod method) {
pdg.startNode = startNode;
}
pdg.addEdge(frontierNode, node, DependencyTypes.CONTROL_DEPENDENCY);
connected = true;
frontierNode.addDependent(node);
node.addBackDependent(frontierNode);
System.out.println("Control Dependency: " + frontierNode + " -> " + node);

}
Expand All @@ -118,11 +124,17 @@ public static PDG constructPdg(SootClass sootClass, SootMethod method) {
pdg.startNode = startNode;
}
pdg.addEdge(node, useNode, DependencyTypes.DATA_DEPENDENCY);
connected = true;
node.addDependent(useNode);
useNode.addBackDependent(node);
System.out.println("Data Dependency: " + node + " -> " + useNode);

}
}

if (!connected) {
System.out.println("> No outgoing edges from: " + node);
}
}

// for (PDGNode node : pdg.getNodes()) {
Expand All @@ -131,6 +143,7 @@ public static PDG constructPdg(SootClass sootClass, SootMethod method) {
// System.out.println(" Dependent: " + dependent);
// }
// }
pdg.setOrderedNodes(orderedNodes);

return pdg;
}
Expand Down
6 changes: 4 additions & 2 deletions src/main/java/org/pdgdiff/graph/GraphTraversal.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public static List<PDGNode> collectNodesBFS(PDG pdg) {

if (debug) System.out.println("[BFS] BFS Graph traversal complete.");
return nodeList;
// return pdg.getNodes();
}

// Method to traverse the graph using a depth-first search and collect all nodes
Expand Down Expand Up @@ -96,8 +97,9 @@ public static List<PDGNode> collectNodesDFS(PDG pdg) {
}

public static int getNodeCount(PDG pdg) {
List<PDGNode> nodeList = collectNodesBFS(pdg);
return nodeList.size();
// List<PDGNode> nodeList = collectNodesBFS(pdg);
// return nodeList.size();
return pdg.getNodes().size();
}

// Optionally, if you have already collected nodes and want to avoid traversal:
Expand Down
114 changes: 88 additions & 26 deletions src/main/java/org/pdgdiff/graph/PDG.java
Original file line number Diff line number Diff line change
@@ -1,34 +1,96 @@
package org.pdgdiff.graph;
package org.pdgdiff.graph;

import soot.toolkits.graph.HashMutableEdgeLabelledDirectedGraph;
import soot.toolkits.graph.UnitGraph;
import soot.toolkits.graph.pdg.PDGNode;
import soot.toolkits.graph.HashMutableEdgeLabelledDirectedGraph;
import soot.toolkits.graph.UnitGraph;
import soot.toolkits.graph.pdg.PDGNode;

import java.util.List;
import java.util.*;

// TODO: this class will be my own version of the HashMutuablePDG that Soot presents, hopefully made slightly more accurate to
// TODO: the original literature.
public class PDG extends HashMutableEdgeLabelledDirectedGraph<PDGNode, GraphGenerator.DependencyTypes> {
private UnitGraph cfg = null;
protected PDGNode startNode = null;
// TODO: this class will be my own version of the HashMutuablePDG that Soot presents, hopefully made slightly more accurate to
// TODO: the original literature.
public class PDG extends HashMutableEdgeLabelledDirectedGraph<PDGNode, GraphGenerator.DependencyTypes> {
private UnitGraph cfg = null;
protected PDGNode startNode = null;
private List<PDGNode> orderedNodes;

public PDG() {
super();
}
public PDG() {
super();
}

public void setCFG(UnitGraph cfg) {
this.cfg = cfg;
}
public void setCFG(UnitGraph cfg) {
this.cfg = cfg;
}

public UnitGraph getCFG() {
return cfg;
}
public UnitGraph getCFG() {
return cfg;
}

public PDGNode getStartNode() {
return startNode;
}
public PDGNode getStartNode() {
return startNode;
}

// public List<PDGNode> getNodes() {
// return super.getNodes();
// }
}
public void setOrderedNodes(List<PDGNode> orderedNodes) {
this.orderedNodes = orderedNodes;
}


public List<PDGNode> getNodes() {
// alternatively could use nodeToPreds method here, not sure
// order seems to be non-det which is a bit worrying.
return orderedNodes;
}

public List<Set<PDGNode>> getConnectedComponents() {
Set<PDGNode> visited = new HashSet<>();
List<Set<PDGNode>> components = new ArrayList<>();

for (PDGNode node : this.getNodes()) {
if (!visited.contains(node)) {
Set<PDGNode> component = new HashSet<>();
exploreComponent(node, visited, component);
components.add(component);
}
}
return components;
}

private void exploreComponent(PDGNode node, Set<PDGNode> visited, Set<PDGNode> component) {
Stack<PDGNode> stack = new Stack<>();
stack.push(node);
visited.add(node);

while (!stack.isEmpty()) {
PDGNode current = stack.pop();
component.add(current);

for (PDGNode neighbor : this.getSuccsOf(current)) {
if (!visited.contains(neighbor)) {
visited.add(neighbor);
stack.push(neighbor);
}
}

for (PDGNode neighbor : this.getPredsOf(current)) {
if (!visited.contains(neighbor)) {
visited.add(neighbor);
stack.push(neighbor);
}
}
}
}

public List<PDGNode> getIsolatedNodes() {
List<PDGNode> isolatedNodes = new ArrayList<>();

for (PDGNode node : this.getNodes()) {
List<PDGNode> successors = this.getSuccsOf(node);
List<PDGNode> predecessors = this.getPredsOf(node);

if ((successors == null || successors.isEmpty()) && (predecessors == null || predecessors.isEmpty())) {
isolatedNodes.add(node);
}
}

return isolatedNodes;
}
}
12 changes: 7 additions & 5 deletions src/main/java/org/pdgdiff/matching/PDGComparator.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,13 @@ public static void compareAndPrintGraphSimilarity(List<PDG> pdgList1, List<PDG>
GraphMatcher matcher = GraphMatcherFactory.createMatcher(strategy, pdgList1, pdgList2);
// for each graph print the size of its nodes and if it has a cycle
pdgList1.forEach(pdg -> {
System.out.println("------");
System.out.println("FILE1 ------");
System.out.println(pdg.getCFG().getBody().getMethod().getSignature());
System.out.println(GraphTraversal.getNodeCount(pdg));
CycleDetection.hasCycle(pdg);
});
pdgList2.forEach(pdg -> {
System.out.println("FILE2 ------");
System.out.println(pdg.getCFG().getBody().getMethod().getSignature());
System.out.println(GraphTraversal.getNodeCount(pdg));
CycleDetection.hasCycle(pdg);
Expand All @@ -49,10 +55,6 @@ public static void compareAndPrintGraphSimilarity(List<PDG> pdgList1, List<PDG>
String method1 = srcPDG.getCFG().getBody().getMethod().getSignature();
String method2 = dstPDG.getCFG().getBody().getMethod().getSignature();
System.out.println("---\n> PDG from class 1: " + method1 + " is matched with PDG from class 2: " + method2);
System.out.println(GraphTraversal.getNodeCount(srcPDG));
CycleDetection.hasCycle(srcPDG);
System.out.println(GraphTraversal.getNodeCount(dstPDG));
CycleDetection.hasCycle(dstPDG);
NodeMapping nodeMapping = graphMapping.getNodeMapping(srcPDG);
if (nodeMapping != null) {
System.out.println("--- Node Mapping:");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ public GraphMapping matchPDGLists() {
// for each pair of unmapped PDGs, compute similarity score
for (PDG pdg1 : unmappedPDGs1) {
for (PDG pdg2 : unmappedPDGs2) {
System.out.println("Matching PDG1: " + pdg1.getCFG().getBody().getMethod().getSignature() + ", PDG2: " + pdg2.getCFG().getBody().getMethod().getSignature());
VF2Matcher vf2Matcher = new VF2Matcher(pdg1, pdg2);
NodeMapping nodeMapping = vf2Matcher.match();

System.out.println(nodeMapping);
if (nodeMapping != null && !nodeMapping.isEmpty()) {
System.out.println(" >> Produced a mapping for " + pdg1.getCFG().getBody().getMethod().getSignature() + " and " + pdg2.getCFG().getBody().getMethod().getSignature());
int mappedNodes = nodeMapping.size();
int unmappedNodes1 = GraphTraversal.getNodeCount(pdg1) - mappedNodes;
int unmappedNodes2 = GraphTraversal.getNodeCount(pdg2) - mappedNodes;
Expand All @@ -42,8 +44,9 @@ public GraphMapping matchPDGLists() {
// this might be to be improved. TODO look into other metrics/ measures.
// TODO might want to add a threshold. possibly not all graphs should be mapped to all graphs!
double score = (double) mappedNodes / (mappedNodes + unmappedNodes1 + unmappedNodes2);

System.out.println(" >> Score: " + score + " for " + pdg1.getCFG().getBody().getMethod().getSignature() + " and " + pdg2.getCFG().getBody().getMethod().getSignature());
if (score > maxScore) {
System.out.println("!!!! >> New best score: " + score);
maxScore = score;
bestPdg1 = pdg1;
bestPdg2 = pdg2;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.pdgdiff.matching.models.ullmann;

import org.pdgdiff.graph.GraphTraversal;
import org.pdgdiff.graph.PDG;
import org.pdgdiff.matching.NodeMapping;
import soot.toolkits.graph.pdg.HashMutablePDG;
Expand Down Expand Up @@ -29,8 +28,9 @@ public UllmannMatcher(PDG pdg1, PDG pdg2) {
this.pdg2 = pdg2;
this.nodeMapping = new NodeMapping();

this.nodes1 = new ArrayList<>(GraphTraversal.collectNodesBFS(pdg1));
this.nodes2 = new ArrayList<>(GraphTraversal.collectNodesBFS(pdg2));
this.nodes1 = new ArrayList<>(pdg1.getNodes());
this.nodes2 = new ArrayList<>(pdg2.getNodes());

this.n = nodes1.size();
this.m = nodes2.size();
this.M = new int[n][m];
Expand Down
Loading