All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
soot.jimple.spark.ondemand.pautil.ContextSensitiveInfo Maven / Gradle / Ivy
package soot.jimple.spark.ondemand.pautil;
/*-
* #%L
* Soot - a J*va Optimization Framework
* %%
* Copyright (C) 2007 Manu Sridharan
* %%
* 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
* .
* #L%
*/
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import soot.SootMethod;
import soot.jimple.InvokeExpr;
import soot.jimple.spark.ondemand.genericutil.ArraySet;
import soot.jimple.spark.ondemand.genericutil.ArraySetMultiMap;
import soot.jimple.spark.pag.GlobalVarNode;
import soot.jimple.spark.pag.LocalVarNode;
import soot.jimple.spark.pag.Node;
import soot.jimple.spark.pag.PAG;
import soot.jimple.spark.pag.VarNode;
import soot.toolkits.scalar.Pair;
import soot.util.HashMultiMap;
/**
* Information for a context-sensitive analysis, eg. for call sites
*
* @author manu
*/
public class ContextSensitiveInfo {
private static final Logger logger = LoggerFactory.getLogger(ContextSensitiveInfo.class);
private static final boolean SKIP_STRING_NODES = false;
private static final boolean SKIP_EXCEPTION_NODES = false;
private static final boolean SKIP_THREAD_GLOBALS = false;
private static final boolean PRINT_CALL_SITE_INFO = false;
/**
* assignment edges, but properly handling multiple calls to a method VarNode -> ArraySet[AssignEdge]
*/
private final ArraySetMultiMap contextSensitiveAssignEdges
= new ArraySetMultiMap();
private final ArraySetMultiMap contextSensitiveAssignBarEdges
= new ArraySetMultiMap();
/**
* nodes in each method
*/
private final ArraySetMultiMap methodToNodes = new ArraySetMultiMap();
private final ArraySetMultiMap methodToOutPorts = new ArraySetMultiMap();
private final ArraySetMultiMap methodToInPorts = new ArraySetMultiMap();
private final ArraySetMultiMap callSitesInMethod = new ArraySetMultiMap();
private final ArraySetMultiMap callSitesInvokingMethod = new ArraySetMultiMap();
private final ArraySetMultiMap callSiteToTargets = new ArraySetMultiMap();
private final ArraySetMultiMap callSiteToEdges = new ArraySetMultiMap();
private final Map virtCallSiteToReceiver = new HashMap();
private final Map callSiteToInvokedMethod = new HashMap();
private final Map callSiteToInvokingMethod = new HashMap();
private final ArraySetMultiMap receiverToVirtCallSites
= new ArraySetMultiMap();
/**
*
*/
public ContextSensitiveInfo(PAG pag) {
// set up method to node map
for (Iterator iter = pag.getVarNodeNumberer().iterator(); iter.hasNext();) {
VarNode varNode = (VarNode) iter.next();
if (varNode instanceof LocalVarNode) {
LocalVarNode local = (LocalVarNode) varNode;
SootMethod method = local.getMethod();
assert method != null : local;
methodToNodes.put(method, local);
if (SootUtil.isRetNode(local)) {
methodToOutPorts.put(method, local);
}
if (SootUtil.isParamNode(local)) {
methodToInPorts.put(method, local);
}
}
}
int callSiteNum = 0;
// first, add regular assigns
Set assignSources = pag.simpleSources();
for (Iterator iter = assignSources.iterator(); iter.hasNext();) {
VarNode assignSource = (VarNode) iter.next();
if (skipNode(assignSource)) {
continue;
}
boolean sourceGlobal = assignSource instanceof GlobalVarNode;
Node[] assignTargets = pag.simpleLookup(assignSource);
for (int i = 0; i < assignTargets.length; i++) {
VarNode assignTarget = (VarNode) assignTargets[i];
if (skipNode(assignTarget)) {
continue;
}
boolean isFinalizerNode = false;
if (assignTarget instanceof LocalVarNode) {
LocalVarNode local = (LocalVarNode) assignTarget;
SootMethod method = local.getMethod();
if (method.toString().indexOf("finalize()") != -1 && SootUtil.isThisNode(local)) {
isFinalizerNode = true;
}
}
boolean targetGlobal = assignTarget instanceof GlobalVarNode;
AssignEdge assignEdge = new AssignEdge(assignSource, assignTarget);
// handle weird finalizers
if (isFinalizerNode) {
assignEdge.setParamEdge();
Integer callSite = new Integer(callSiteNum++);
assignEdge.setCallSite(callSite);
}
addAssignEdge(assignEdge);
if (sourceGlobal) {
if (targetGlobal) {
// System.err.println("G2G " + assignSource + " --> "
// + assignTarget);
} else {
SootMethod method = ((LocalVarNode) assignTarget).getMethod();
// don't want to include things assigned something that
// is already an in port
if (!methodToInPorts.get(method).contains(assignTarget)) {
methodToInPorts.put(method, assignSource);
}
}
} else {
if (targetGlobal) {
SootMethod method = ((LocalVarNode) assignSource).getMethod();
// don't want to include things assigned from something
// that
// is already an out port
if (!methodToOutPorts.get(method).contains(assignSource)) {
methodToOutPorts.put(method, assignTarget);
}
}
}
}
}
// now handle calls
HashMultiMap callAssigns = pag.callAssigns;
PrintWriter callSiteWriter = null;
if (PRINT_CALL_SITE_INFO) {
try {
callSiteWriter = new PrintWriter(new FileWriter("callSiteInfo"), true);
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
for (Iterator iter = callAssigns.keySet().iterator(); iter.hasNext();) {
InvokeExpr ie = (InvokeExpr) iter.next();
Integer callSite = new Integer(callSiteNum++);
callSiteToInvokedMethod.put(callSite, ie.getMethod());
SootMethod invokingMethod = pag.callToMethod.get(ie);
callSiteToInvokingMethod.put(callSite, invokingMethod);
if (PRINT_CALL_SITE_INFO) {
callSiteWriter.println(callSite + " " + callSiteToInvokingMethod.get(callSite) + " " + ie);
}
if (pag.virtualCallsToReceivers.containsKey(ie)) {
LocalVarNode receiver = (LocalVarNode) pag.virtualCallsToReceivers.get(ie);
assert receiver != null;
virtCallSiteToReceiver.put(callSite, receiver);
receiverToVirtCallSites.put(receiver, callSite);
}
Set curEdges = callAssigns.get(ie);
for (Iterator iterator = curEdges.iterator(); iterator.hasNext();) {
Pair callAssign = (Pair) iterator.next();
// for reflective calls, the "O1" value can actually be a FieldRefNode
// we simply ignore such cases here (appears to be sound)
if (!(callAssign.getO1() instanceof VarNode)) {
continue;
}
VarNode src = (VarNode) callAssign.getO1();
VarNode dst = (VarNode) callAssign.getO2();
if (skipNode(src)) {
continue;
}
ArraySet edges = getAssignBarEdges(src);
AssignEdge edge = null;
for (int i = 0; i < edges.size() && edge == null; i++) {
AssignEdge curEdge = (AssignEdge) edges.get(i);
if (curEdge.getDst() == dst) {
edge = curEdge;
}
}
assert edge != null : "no edge from " + src + " to " + dst;
boolean edgeFromOtherCallSite = edge.isCallEdge();
if (edgeFromOtherCallSite) {
edge = new AssignEdge(src, dst);
}
edge.setCallSite(callSite);
callSiteToEdges.put(callSite, edge);
if (SootUtil.isParamNode(dst)) {
// assert src instanceof LocalVarNode : src + " " + dst;
edge.setParamEdge();
SootMethod invokedMethod = ((LocalVarNode) dst).getMethod();
callSiteToTargets.put(callSite, invokedMethod);
callSitesInvokingMethod.put(invokedMethod, callSite);
// assert src instanceof LocalVarNode : src + " NOT LOCAL";
if (src instanceof LocalVarNode) {
callSitesInMethod.put(((LocalVarNode) src).getMethod(), callSite);
}
} else if (SootUtil.isRetNode(src)) {
edge.setReturnEdge();
SootMethod invokedMethod = ((LocalVarNode) src).getMethod();
callSiteToTargets.put(callSite, invokedMethod);
callSitesInvokingMethod.put(invokedMethod, callSite);
if (dst instanceof LocalVarNode) {
callSitesInMethod.put(((LocalVarNode) dst).getMethod(), callSite);
}
} else {
assert false : "weird call edge " + callAssign;
}
if (edgeFromOtherCallSite) {
addAssignEdge(edge);
}
}
}
// System.err.println(callSiteNum + " call sites");
assert callEdgesReasonable();
if (PRINT_CALL_SITE_INFO) {
callSiteWriter.close();
}
// assert assignEdgesWellFormed(pag) == null :
// assignEdgesWellFormed(pag);
}
private boolean callEdgesReasonable() {
Set vars = contextSensitiveAssignEdges.keySet();
for (VarNode node : vars) {
ArraySet assigns = contextSensitiveAssignEdges.get(node);
for (AssignEdge edge : assigns) {
if (edge.isCallEdge()) {
if (edge.getCallSite() == null) {
logger.debug("" + edge + " is weird!!");
return false;
}
}
}
}
return true;
}
@SuppressWarnings("unused")
private String assignEdgesWellFormed(PAG pag) {
for (Iterator iter = pag.getVarNodeNumberer().iterator(); iter.hasNext();) {
VarNode v = (VarNode) iter.next();
Set outgoingAssigns = getAssignBarEdges(v);
for (AssignEdge edge : outgoingAssigns) {
if (edge.getSrc() != v) {
return edge + " src should be " + v;
}
}
Set incomingAssigns = getAssignEdges(v);
for (AssignEdge edge : incomingAssigns) {
if (edge.getDst() != v) {
return edge + " dst should be " + v;
}
}
}
return null;
}
/**
* @param node
* @return
*/
private boolean skipNode(VarNode node) {
return (SKIP_STRING_NODES && SootUtil.isStringNode(node)) || (SKIP_EXCEPTION_NODES && SootUtil.isExceptionNode(node))
|| (SKIP_THREAD_GLOBALS && SootUtil.isThreadGlobal(node));
}
/**
* @param assignSource
* @param assignTarget
*/
private void addAssignEdge(AssignEdge assignEdge) {
contextSensitiveAssignEdges.put(assignEdge.getSrc(), assignEdge);
contextSensitiveAssignBarEdges.put(assignEdge.getDst(), assignEdge);
}
public ArraySet getAssignBarEdges(VarNode node) {
return contextSensitiveAssignEdges.get(node);
}
/**
*
* @param node
* @return edges capturing assign flow into node
*/
public ArraySet getAssignEdges(VarNode node) {
return contextSensitiveAssignBarEdges.get(node);
}
public Set methods() {
return methodToNodes.keySet();
}
public ArraySet getNodesForMethod(SootMethod method) {
return methodToNodes.get(method);
}
public ArraySet getInPortsForMethod(SootMethod method) {
return methodToInPorts.get(method);
}
public ArraySet getOutPortsForMethod(SootMethod method) {
return methodToOutPorts.get(method);
}
/**
* @param method
* @return
*/
public ArraySet getCallSitesInMethod(SootMethod method) {
return callSitesInMethod.get(method);
}
public Set getCallSitesInvokingMethod(SootMethod method) {
return callSitesInvokingMethod.get(method);
}
public ArraySet getCallSiteEdges(Integer callSite) {
return callSiteToEdges.get(callSite);
}
public ArraySet getCallSiteTargets(Integer callSite) {
return callSiteToTargets.get(callSite);
}
public LocalVarNode getReceiverForVirtCallSite(Integer callSite) {
LocalVarNode ret = virtCallSiteToReceiver.get(callSite);
assert ret != null;
return ret;
}
public Set getVirtCallSitesForReceiver(LocalVarNode receiver) {
return receiverToVirtCallSites.get(receiver);
}
public SootMethod getInvokedMethod(Integer callSite) {
return callSiteToInvokedMethod.get(callSite);
}
public SootMethod getInvokingMethod(Integer callSite) {
return callSiteToInvokingMethod.get(callSite);
}
public boolean isVirtCall(Integer callSite) {
return virtCallSiteToReceiver.containsKey(callSite);
}
}