qilin.pta.toolkits.zipper.analysis.PotentialContextElement Maven / Gradle / Ivy
package qilin.pta.toolkits.zipper.analysis;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import qilin.core.PTA;
import qilin.core.builder.MethodNodeFactory;
import qilin.core.pag.AllocNode;
import qilin.core.pag.ContextMethod;
import qilin.core.pag.VarNode;
import qilin.core.sets.PointsToSet;
import qilin.pta.toolkits.common.OAG;
import qilin.pta.toolkits.zipper.Global;
import qilin.util.collect.SetFactory;
import qilin.util.graph.MergedNode;
import qilin.util.graph.SCCMergedGraph;
import qilin.util.graph.TopologicalSorter;
import sootup.core.model.SootMethod;
import sootup.core.types.Type;
/**
* For each object o, this class compute the set of methods which o could potentially be their
* context element.
*
* Conversely, for each method m, this class compute the set of objects which could potentially
* be its context element.
*/
public class PotentialContextElement {
private final PTA pta;
// This map maps each object to the methods invoked on it.
// For instance methods, they are the methods whose receiver is the object.
// For static methods, they are the methods reachable from instance methods.
private Map> invokedMethods;
private Map> obj2invokedMethods;
private final Map> typePCEMethods;
private final Map> pceOfMap;
private final OAG oag;
private final Map> typeAllocatees;
private final Map> allocateeMap;
PotentialContextElement(final PTA pta, final OAG oag) {
this.pta = pta;
this.oag = oag;
this.typePCEMethods = new ConcurrentHashMap<>();
this.obj2invokedMethods = new ConcurrentHashMap<>();
this.pceOfMap = new ConcurrentHashMap<>();
this.typeAllocatees = new ConcurrentHashMap<>();
this.allocateeMap = new ConcurrentHashMap<>();
this.init(oag);
}
public Set PCEMethodsOf(final AllocNode obj) {
return this.pceOfMap.getOrDefault(obj, Collections.emptySet());
}
/**
* @param type
* @return PCE methods of the objects of given type.
*/
public Set PCEMethodsOf(final Type type) {
if (!this.typePCEMethods.containsKey(type)) {
final Set methods = ConcurrentHashMap.newKeySet();
pta.getPag().getAllocNodes().stream()
.filter(o -> o.getType().equals(type))
.forEach(obj -> methods.addAll(this.PCEMethodsOf(obj)));
this.typePCEMethods.put(type, methods);
}
return this.typePCEMethods.getOrDefault(type, Collections.emptySet());
}
/** Compute PCE methods for each objects. */
private void init(final OAG oag) {
final SCCMergedGraph mg = new SCCMergedGraph<>(oag);
final TopologicalSorter> topoSorter = new TopologicalSorter<>();
final SetFactory setFactory = new SetFactory<>();
final SetFactory setFactory2 = new SetFactory<>();
this.buildMethodsInvokedOnObjects();
this.invokedMethods = new HashMap<>();
topoSorter
.sort(mg, true)
.forEach(
node -> {
final Set methods = ConcurrentHashMap.newKeySet();
methods.addAll(setFactory.get(this.getPCEMethods(node, mg)));
final Set allocatees = ConcurrentHashMap.newKeySet();
allocatees.addAll(setFactory2.get(this.getAllocatees(node, mg)));
node.getContent()
.forEach(
obj -> {
pceOfMap.put(obj, methods);
allocateeMap.put(obj, allocatees);
});
});
this.invokedMethods = null;
if (Global.isDebug()) {
this.computePCEObjects();
}
oag.allNodes()
.forEach(
obj -> {
final Type type = obj.getType();
this.typeAllocatees.putIfAbsent(type, new HashSet<>());
this.typeAllocatees.get(type).addAll(this.allocateesOf(obj));
});
}
private Set getAllocatees(
final MergedNode node, final SCCMergedGraph mg) {
final Set allocatees = new HashSet<>();
mg.succsOf(node)
.forEach(
n -> {
// direct allocatees
allocatees.addAll(n.getContent());
// indirect allocatees, here, it does not require to traverse all heaps in
// n.getContent()
// because of lines 104-107.
final AllocNode o = n.getContent().iterator().next();
allocatees.addAll(this.allocateesOf(o));
});
final AllocNode obj = node.getContent().iterator().next();
if (node.getContent().size() > 1 || oag.succsOf(obj).contains(obj)) {
// The merged node is a true SCC
allocatees.addAll(node.getContent());
}
return allocatees;
}
private Set allocateesOf(final AllocNode obj) {
return this.allocateeMap.getOrDefault(obj, Collections.emptySet());
}
public Set allocateesOf(final Type type) {
return this.typeAllocatees.getOrDefault(type, Collections.emptySet());
}
private Set getPCEMethods(
final MergedNode node, final SCCMergedGraph mg) {
final Set methods = new HashSet<>();
mg.succsOf(node)
.forEach(
n -> {
final AllocNode o2 = n.getContent().iterator().next();
methods.addAll(this.PCEMethodsOf(o2));
});
node.getContent().forEach(o -> methods.addAll(this.invokedMethodsOf(o)));
return methods;
}
public Set methodsInvokedOn(final AllocNode obj) {
return this.obj2invokedMethods.getOrDefault(obj, Collections.emptySet());
}
private void buildMethodsInvokedOnObjects() {
this.obj2invokedMethods = new HashMap<>();
pta.getNakedReachableMethods().stream()
.filter(m -> !m.isStatic())
.forEach(
instMtd -> {
MethodNodeFactory mthdNF = pta.getPag().getMethodPAG(instMtd).nodeFactory();
VarNode thisVar = mthdNF.caseThis();
PointsToSet pts = pta.reachingObjects(thisVar).toCIPointsToSet();
for (Iterator it = pts.iterator(); it.hasNext(); ) {
AllocNode obj = it.next();
obj2invokedMethods.computeIfAbsent(obj, k -> new HashSet<>()).add(instMtd);
}
});
}
private Set invokedMethodsOf(final AllocNode obj) {
if (!this.invokedMethods.containsKey(obj)) {
final Set methods = new HashSet<>();
final Queue queue = new LinkedList<>(this.methodsInvokedOn(obj));
while (!queue.isEmpty()) {
final SootMethod method = queue.poll();
methods.add(method);
pta.getCallGraph()
.edgesOutOf(new ContextMethod(method, pta.emptyContext()))
.forEachRemaining(
edge -> {
SootMethod callee = edge.getTgt().method();
if (callee.isStatic() && !methods.contains(callee)) {
queue.offer(callee);
}
});
}
this.invokedMethods.put(obj, methods);
}
return this.invokedMethods.get(obj);
}
private void computePCEObjects() {
final Map> pceObjs = new HashMap<>();
pta.getPag()
.getAllocNodes()
.forEach(
obj ->
this.PCEMethodsOf(obj)
.forEach(
method -> {
if (!pceObjs.containsKey(method)) {
pceObjs.put(method, new HashSet<>());
}
pceObjs.get(method).add(obj);
}));
}
}