![JAR search and dependency download from the Maven repository](/logo.png)
soot.jimple.toolkits.infoflow.InfoFlowAnalysis Maven / Gradle / Ivy
package soot.jimple.toolkits.infoflow;
import java.util.*;
import soot.*;
import soot.util.dot.*;
import soot.toolkits.graph.*;
import soot.jimple.internal.*;
import soot.jimple.toolkits.callgraph.CallGraph;
import soot.jimple.toolkits.callgraph.Edge;
import soot.jimple.*;
// InfoFlowAnalysis written by Richard L. Halpert, 2007-02-24
// Constructs data flow tables for each method of every application class. Ignores indirect flow.
// These tables conservatively approximate how data flows from parameters,
// fields, and globals to parameters, fields, globals, and the return value.
// Note that a ref-type parameter (or field or global) might allow access to a
// large data structure, but that entire structure will be represented only by
// the parameter's one node in the data flow graph.
// Provides a high level interface to access the data flow information.
public class InfoFlowAnalysis
{
boolean includePrimitiveInfoFlow;
boolean includeInnerFields;
boolean printDebug;
Map classToClassInfoFlowAnalysis;
public InfoFlowAnalysis(boolean includePrimitiveDataFlow, boolean includeInnerFields)
{
this(includePrimitiveDataFlow, includeInnerFields, false);
}
public InfoFlowAnalysis(boolean includePrimitiveDataFlow, boolean includeInnerFields, boolean printDebug)
{
this.includePrimitiveInfoFlow = includePrimitiveDataFlow;
this.includeInnerFields = includeInnerFields;
this.printDebug = printDebug;
classToClassInfoFlowAnalysis = new HashMap();
}
public boolean includesPrimitiveInfoFlow()
{
return includePrimitiveInfoFlow;
}
public boolean includesInnerFields()
{
return includeInnerFields;
}
public boolean printDebug()
{
return printDebug;
}
/*
public void doApplicationClassesAnalysis()
{
Iterator appClassesIt = Scene.v().getApplicationClasses().iterator();
while (appClassesIt.hasNext())
{
SootClass appClass = (SootClass) appClassesIt.next();
// Create the needed flow analysis object
ClassInfoFlowAnalysis cdfa = new ClassInfoFlowAnalysis(appClass, this);
// Put the preliminary flow-insensitive results here in case they
// are needed by the flow-sensitive version. This method will be
// reentrant if any method we are analyzing is reentrant, so we
// must do this to prevent an infinite recursive loop.
classToClassInfoFlowAnalysis.put(appClass, cdfa);
}
Iterator appClassesIt2 = Scene.v().getApplicationClasses().iterator();
while (appClassesIt2.hasNext())
{
SootClass appClass = (SootClass) appClassesIt2.next();
// Now calculate the flow-sensitive version. If this classes methods
// are reentrant, it will call this method and receive the flow
// insensitive version that is already cached.
ClassInfoFlowAnalysis cdfa = (ClassInfoFlowAnalysis) classToClassInfoFlowAnalysis.get(appClass);
cdfa.doFixedPointDataFlowAnalysis();
}
}
*/
private ClassInfoFlowAnalysis getClassInfoFlowAnalysis(SootClass sc)
{
if(!classToClassInfoFlowAnalysis.containsKey(sc))
{
ClassInfoFlowAnalysis cdfa = new ClassInfoFlowAnalysis(sc, this);
classToClassInfoFlowAnalysis.put(sc, cdfa);
}
return classToClassInfoFlowAnalysis.get(sc);
}
public SmartMethodInfoFlowAnalysis getMethodInfoFlowAnalysis(SootMethod sm)
{
ClassInfoFlowAnalysis cdfa = getClassInfoFlowAnalysis(sm.getDeclaringClass());
return cdfa.getMethodInfoFlowAnalysis(sm);
}
/** Returns a BACKED MutableDirectedGraph whose nodes are EquivalentValue
* wrapped Refs. It's perfectly safe to modify this graph, just so long as
* new nodes are EquivalentValue wrapped Refs. */
public HashMutableDirectedGraph getMethodInfoFlowSummary(SootMethod sm) { return getMethodInfoFlowSummary(sm, true); }
public HashMutableDirectedGraph getMethodInfoFlowSummary(SootMethod sm, boolean doFullAnalysis)
{
ClassInfoFlowAnalysis cdfa = getClassInfoFlowAnalysis(sm.getDeclaringClass());
return cdfa.getMethodInfoFlowSummary(sm, doFullAnalysis);
}
/** Returns an unmodifiable list of EquivalentValue wrapped Refs that source
* flows to when method sm is called. */
/* public List getSinksOf(SootMethod sm, EquivalentValue source)
{
ClassInfoFlowAnalysis cdfa = getClassDataFlowAnalysis(sm.getDeclaringClass());
MutableDirectedGraph g = cdfa.getMethodDataFlowGraph(sm);
List sinks = null;
if(g.containsNode(source))
sinks = g.getSuccsOf(source);
else
sinks = new ArrayList();
return sinks;
}
*/
/** Returns an unmodifiable list of EquivalentValue wrapped Refs that sink
* flows from when method sm is called. */
/* public List getSourcesOf(SootMethod sm, EquivalentValue sink)
{
ClassInfoFlowAnalysis cdfa = getClassDataFlowAnalysis(sm.getDeclaringClass());
MutableDirectedGraph g = cdfa.getMethodDataFlowGraph(sm);
List sources = null;
if(g.containsNode(sink))
sources = g.getPredsOf(sink);
else
sources = new ArrayList();
return sources;
}
*/
// Returns an EquivalentValue wrapped Ref based on sfr
// that is suitable for comparison to the nodes of a Data Flow Graph
public static EquivalentValue getNodeForFieldRef(SootMethod sm, SootField sf) { return getNodeForFieldRef(sm, sf, null); }
public static EquivalentValue getNodeForFieldRef(SootMethod sm, SootField sf, Local realLocal)
{
if(sf.isStatic())
{
return new CachedEquivalentValue( Jimple.v().newStaticFieldRef(sf.makeRef()) );
}
else
{
// Jimple.v().newThisRef(sf.getDeclaringClass().getType())
if(sm.isConcrete() && !sm.isStatic() && sm.getDeclaringClass() == sf.getDeclaringClass() && realLocal == null)
{
JimpleLocal fakethis = new FakeJimpleLocal("fakethis", sf.getDeclaringClass().getType(), sm.retrieveActiveBody().getThisLocal());
return new CachedEquivalentValue( Jimple.v().newInstanceFieldRef(fakethis, sf.makeRef()) ); // fake thisLocal
}
else
{
// Pretends to be a this. ref for a method without a body,
// for a static method, or for an inner field
JimpleLocal fakethis = new FakeJimpleLocal("fakethis", sf.getDeclaringClass().getType(), realLocal);
return new CachedEquivalentValue( Jimple.v().newInstanceFieldRef(fakethis, sf.makeRef()) ); // fake thisLocal
}
}
}
// Returns an EquivalentValue wrapped Ref for @parameter i
// that is suitable for comparison to the nodes of a Data Flow Graph
public static EquivalentValue getNodeForParameterRef(SootMethod sm, int i)
{
return new CachedEquivalentValue(new ParameterRef(sm.getParameterType(i), i));
}
// Returns an EquivalentValue wrapped Ref for the return value
// that is suitable for comparison to the nodes of a Data Flow Graph
public static EquivalentValue getNodeForReturnRef(SootMethod sm)
{
return new CachedEquivalentValue(new ParameterRef(sm.getReturnType(), -1));
}
// Returns an EquivalentValue wrapped ThisRef
// that is suitable for comparison to the nodes of a Data Flow Graph
public static EquivalentValue getNodeForThisRef(SootMethod sm)
{
return new CachedEquivalentValue(new ThisRef(sm.getDeclaringClass().getType()));
}
protected HashMutableDirectedGraph getInvokeInfoFlowSummary(InvokeExpr ie, Stmt is, SootMethod context)
{
// get the data flow graph for each possible target of ie,
// then combine them conservatively and return the result.
HashMutableDirectedGraph ret = null;
SootMethodRef methodRef = ie.getMethodRef();
String subSig = methodRef.resolve().getSubSignature();
CallGraph cg = Scene.v().getCallGraph();
for(Iterator edges = cg.edgesOutOf(is); edges.hasNext();)
{
Edge e = edges.next();
SootMethod target = e.getTgt().method();
// Verify that this target is an implementation of the method we intend to call,
// and not just a class initializer or other unintended control flow.
if(target.getSubSignature().equals(subSig))
{
HashMutableDirectedGraph ifs = getMethodInfoFlowSummary(target, context.getDeclaringClass().isApplicationClass());
if(ret == null)
ret = ifs;
else
{
for(Object node : ifs.getNodes())
{
if(!ret.containsNode(node))
ret.addNode(node);
for(Object succ : ifs.getSuccsOf(node))
ret.addEdge(node, succ);
}
}
}
}
return ret;
// return getMethodInfoFlowSummary(methodRef.resolve(), context.getDeclaringClass().isApplicationClass());
}
protected MutableDirectedGraph getInvokeAbbreviatedInfoFlowGraph(InvokeExpr ie, SootMethod context)
{
// get the data flow graph for each possible target of ie,
// then combine them conservatively and return the result.
SootMethodRef methodRef = ie.getMethodRef();
return getMethodInfoFlowAnalysis(methodRef.resolve()).getMethodAbbreviatedInfoFlowGraph();
}
public static void printInfoFlowSummary(DirectedGraph g)
{
Iterator nodeIt = g.iterator();
if(!nodeIt.hasNext())
G.v().out.println(" " + " --> ");
while(nodeIt.hasNext())
{
Object node = nodeIt.next();
List sources = g.getPredsOf(node);
Iterator sourcesIt = sources.iterator();
if(!sourcesIt.hasNext())
continue;
G.v().out.print(" [ ");
int sourcesnamelength = 0;
int lastnamelength = 0;
while(sourcesIt.hasNext())
{
Value v = ((EquivalentValue) sourcesIt.next()).getValue();
if(v instanceof FieldRef)
{
FieldRef fr = (FieldRef) v;
String name = fr.getFieldRef().name();
lastnamelength = name.length();
if(lastnamelength > sourcesnamelength)
sourcesnamelength = lastnamelength;
G.v().out.print(name);
}
else if(v instanceof ParameterRef)
{
ParameterRef pr = (ParameterRef) v;
lastnamelength = 11;
if(lastnamelength > sourcesnamelength)
sourcesnamelength = lastnamelength;
G.v().out.print("@parameter" + pr.getIndex());
}
else
{
String name = v.toString();
lastnamelength = name.length();
if(lastnamelength > sourcesnamelength)
sourcesnamelength = lastnamelength;
G.v().out.print(name);
}
if(sourcesIt.hasNext())
G.v().out.print("\n ");
}
for(int i = 0; i < sourcesnamelength - lastnamelength; i++)
G.v().out.print(" ");
G.v().out.println(" ] --> " + node.toString());
}
}
public static void printGraphToDotFile(String filename, DirectedGraph graph, String graphname, boolean onePage)
{
// this makes the node name unique
nodecount = 0; // reset node counter first.
Hashtable nodeindex = new Hashtable(graph.size());
// file name is the method name + .dot
DotGraph canvas = new DotGraph(filename);
if (!onePage) {
canvas.setPageSize(8.5, 11.0);
}
canvas.setNodeShape(DotGraphConstants.NODE_SHAPE_BOX);
canvas.setGraphLabel(graphname);
Iterator nodesIt = graph.iterator();
while (nodesIt.hasNext())
{
Object node = nodesIt.next();
canvas.drawNode(getNodeName(node));
canvas.getNode(getNodeName(node)).setLabel(getNodeLabel(node));
Iterator succsIt = graph.getSuccsOf(node).iterator();
while (succsIt.hasNext())
{
Object s= succsIt.next();
canvas.drawNode(getNodeName(s));
canvas.getNode(getNodeName(s)).setLabel(getNodeLabel(s));
canvas.drawEdge(getNodeName(node), getNodeName(s));
}
}
canvas.plot(filename + ".dot");
}
static int nodecount = 0;
static Map nodeToNodeName = new HashMap();
public static String getNodeName(Object o)
{
// if(!nodeToNodeName.containsKey(o)) // Since this uses all different kinds of objects, we
// // were getting weird collisions, causing wrong graphs.
// nodeToNodeName.put(o, "N" + (nodecount++));
//
// return (String) nodeToNodeName.get(o);
return getNodeLabel(o);
}
public static String getNodeLabel(Object o)
{
Value node = ((EquivalentValue) o).getValue();
/*
if(node instanceof InstanceFieldRef)
{
InstanceFieldRef ifr = (InstanceFieldRef) node;
if(ifr.getBase() instanceof FakeJimpleLocal)
return ifr.getField().getDeclaringClass().getShortName() + "." + ifr.getFieldRef().name();
else
return ifr.getField().getDeclaringClass().getShortName() + "." + ifr.getFieldRef().name();
}
else
*/
if(node instanceof FieldRef)
{
FieldRef fr = (FieldRef) node;
return fr.getField().getDeclaringClass().getShortName() + "." + fr.getFieldRef().name();
}
return node.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy