soot.jimple.toolkits.infoflow.SimpleMethodInfoFlowAnalysis Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of robovm-soot Show documentation
Show all versions of robovm-soot Show documentation
RoboVM fork of Soot - A Java optimization framework
package soot.jimple.toolkits.infoflow;
import soot.*;
import java.util.*;
import soot.toolkits.graph.*;
import soot.toolkits.scalar.*;
import soot.jimple.internal.*;
import soot.jimple.*;
// SimpleMethodInfoFlowAnalysis written by Richard L. Halpert, 2007-02-25
// Constructs a data flow table for the given method. 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.
public class SimpleMethodInfoFlowAnalysis extends ForwardFlowAnalysis
{
SootMethod sm;
Value thisLocal;
InfoFlowAnalysis dfa;
boolean refOnly;
MutableDirectedGraph infoFlowGraph;
Ref returnRef;
FlowSet entrySet;
FlowSet emptySet;
boolean printMessages;
public static int counter = 0;
public SimpleMethodInfoFlowAnalysis(UnitGraph g, InfoFlowAnalysis dfa, boolean ignoreNonRefTypeFlow)
{
this(g, dfa, ignoreNonRefTypeFlow, true);
counter++;
// Add all of the nodes necessary to ensure that this is a complete data flow graph
// Add every parameter of this method
for(int i = 0; i < sm.getParameterCount(); i++)
{
EquivalentValue parameterRefEqVal = InfoFlowAnalysis.getNodeForParameterRef(sm, i);
if(!infoFlowGraph.containsNode(parameterRefEqVal))
infoFlowGraph.addNode(parameterRefEqVal);
}
// Add every field of this class
for(Iterator it = sm.getDeclaringClass().getFields().iterator(); it.hasNext(); )
{
SootField sf = (SootField) it.next();
EquivalentValue fieldRefEqVal = InfoFlowAnalysis.getNodeForFieldRef(sm, sf);
if(!infoFlowGraph.containsNode(fieldRefEqVal))
infoFlowGraph.addNode(fieldRefEqVal);
}
// Add every field of this class's superclasses
SootClass superclass = sm.getDeclaringClass();
if(superclass.hasSuperclass())
superclass = sm.getDeclaringClass().getSuperclass();
while(superclass.hasSuperclass()) // we don't want to process Object
{
Iterator scFieldsIt = superclass.getFields().iterator();
while(scFieldsIt.hasNext())
{
SootField scField = (SootField) scFieldsIt.next();
EquivalentValue fieldRefEqVal = InfoFlowAnalysis.getNodeForFieldRef(sm, scField);
if(!infoFlowGraph.containsNode(fieldRefEqVal))
infoFlowGraph.addNode(fieldRefEqVal);
}
superclass = superclass.getSuperclass();
}
// Add thisref of this class
EquivalentValue thisRefEqVal = InfoFlowAnalysis.getNodeForThisRef(sm);
if(!infoFlowGraph.containsNode(thisRefEqVal))
infoFlowGraph.addNode(thisRefEqVal);
// Add returnref of this method
EquivalentValue returnRefEqVal = new CachedEquivalentValue(returnRef);
if(!infoFlowGraph.containsNode(returnRefEqVal))
infoFlowGraph.addNode(returnRefEqVal);
if(printMessages)
G.v().out.println("STARTING ANALYSIS FOR " + g.getBody().getMethod() + " -----");
doFlowInsensitiveAnalysis();
if(printMessages)
G.v().out.println("ENDING ANALYSIS FOR " + g.getBody().getMethod() + " -----");
}
/** A constructor that doesn't run the analysis */
protected SimpleMethodInfoFlowAnalysis(UnitGraph g, InfoFlowAnalysis dfa, boolean ignoreNonRefTypeFlow, boolean dummyDontRunAnalysisYet)
{
super(g);
this.sm = g.getBody().getMethod();
if(sm.isStatic())
this.thisLocal = null;
else
this.thisLocal = g.getBody().getThisLocal();
this.dfa = dfa;
this.refOnly = ignoreNonRefTypeFlow;
this.infoFlowGraph = new MemoryEfficientGraph();
this.returnRef = new ParameterRef(g.getBody().getMethod().getReturnType(), -1); // it's a dummy parameter ref
this.entrySet = new ArraySparseSet();
this.emptySet = new ArraySparseSet();
printMessages = false;
}
public void doFlowInsensitiveAnalysis()
{
FlowSet fs = (FlowSet) newInitialFlow();
boolean flowSetChanged = true;
while(flowSetChanged)
{
int sizebefore = fs.size();
Iterator stmtIt = graph.iterator();
while(stmtIt.hasNext())
{
Stmt s = (Stmt) stmtIt.next();
flowThrough(fs, s, fs);
}
if(fs.size() > sizebefore)
flowSetChanged = true;
else
flowSetChanged = false;
}
}
public MutableDirectedGraph getMethodInfoFlowSummary()
{
return infoFlowGraph;
}
protected void merge(Object in1, Object in2, Object out)
{
FlowSet inSet1 = (FlowSet) in1;
FlowSet inSet2 = (FlowSet) in2;
FlowSet outSet = (FlowSet) out;
inSet1.union(inSet2, outSet);
}
protected boolean isNonRefType(Type type)
{
return !(type instanceof RefLikeType);
}
protected boolean ignoreThisDataType(Type type)
{
return refOnly && isNonRefType(type);
}
// Interesting sources are summarized (and possibly printed)
public boolean isInterestingSource(Value source)
{
return (source instanceof Ref);
}
// Trackable sources are added to the flow set
public boolean isTrackableSource(Value source)
{
return isInterestingSource(source) || (source instanceof Ref);
}
// Interesting sinks are possibly printed
public boolean isInterestingSink(Value sink)
{
return (sink instanceof Ref);
}
// Trackable sinks are added to the flow set
public boolean isTrackableSink(Value sink)
{
return isInterestingSink(sink) || (sink instanceof Ref) || (sink instanceof Local);
}
private ArrayList getDirectSources(Value v, FlowSet fs)
{
ArrayList ret = new ArrayList(); // of "interesting sources"
EquivalentValue vEqVal = new CachedEquivalentValue(v);
Iterator fsIt = fs.iterator();
while(fsIt.hasNext())
{
Pair pair = (Pair) fsIt.next();
if( pair.getO1().equals(vEqVal) )
ret.add( ((EquivalentValue)pair.getO2()).getValue() );
}
return ret;
}
// For when data flows to a local
protected void handleFlowsToValue(Value sink, Value initialSource, FlowSet fs)
{
if(!isTrackableSink(sink))
return;
List sources = getDirectSources(initialSource, fs); // list of Refs... returns all other sources
if(isTrackableSource(initialSource))
sources.add(initialSource);
Iterator sourcesIt = sources.iterator();
while(sourcesIt.hasNext())
{
Value source = sourcesIt.next();
EquivalentValue sinkEqVal = new CachedEquivalentValue(sink);
EquivalentValue sourceEqVal = new CachedEquivalentValue(source);
if(sinkEqVal.equals(sourceEqVal))
continue;
Pair pair = new Pair(sinkEqVal, sourceEqVal);
if(!fs.contains(pair))
{
fs.add(pair);
if(isInterestingSource(source) && isInterestingSink(sink))
{
if(!infoFlowGraph.containsNode(sinkEqVal))
infoFlowGraph.addNode(sinkEqVal);
if(!infoFlowGraph.containsNode(sourceEqVal))
infoFlowGraph.addNode(sourceEqVal);
infoFlowGraph.addEdge(sourceEqVal, sinkEqVal);
if(printMessages)
G.v().out.println(" Found " + source + " flows to " + sink);
}
}
}
}
// for when data flows to the data structure pointed to by a local
protected void handleFlowsToDataStructure(Value base, Value initialSource, FlowSet fs)
{
List sinks = getDirectSources(base, fs);
if(isTrackableSink(base))
sinks.add(base);
List sources = getDirectSources(initialSource, fs);
if(isTrackableSource(initialSource))
sources.add(initialSource);
Iterator sourcesIt = sources.iterator();
while(sourcesIt.hasNext())
{
Value source = sourcesIt.next();
EquivalentValue sourceEqVal = new CachedEquivalentValue(source);
Iterator sinksIt = sinks.iterator();
while(sinksIt.hasNext())
{
Value sink = sinksIt.next();
if(!isTrackableSink(sink))
continue;
EquivalentValue sinkEqVal = new CachedEquivalentValue(sink);
if(sinkEqVal.equals(sourceEqVal))
continue;
Pair pair = new Pair(sinkEqVal, sourceEqVal);
if(!fs.contains(pair))
{
fs.add(pair);
if(isInterestingSource(source) && isInterestingSink(sink))
{
if(!infoFlowGraph.containsNode(sinkEqVal))
infoFlowGraph.addNode(sinkEqVal);
if(!infoFlowGraph.containsNode(sourceEqVal))
infoFlowGraph.addNode(sourceEqVal);
infoFlowGraph.addEdge(sourceEqVal, sinkEqVal);
if(printMessages)
G.v().out.println(" Found " + source + " flows to " + sink);
}
}
}
}
}
// handles the invoke expression AND returns a list of the return value's sources
// for each node
// if the node is a parameter
// source = argument
// if the node is a static field
// source = node
// if the node is a field
// source = receiver object
// if the node is the return value
// continue
// for each sink
// if the sink is a parameter
// handleFlowsToDataStructure(sink, source, fs)
// if the sink is a static field
// handleFlowsToValue(sink, source, fs)
// if the sink is a field
// handleFlowsToDataStructure(receiver object, source, fs)
// if the sink is the return value
// add node to list of return value sources
protected List handleInvokeExpr(InvokeExpr ie, Stmt is, FlowSet fs)
{
// get the data flow graph
MutableDirectedGraph dataFlowGraph = dfa.getInvokeInfoFlowSummary(ie, is, sm); // must return a graph whose nodes are Refs!!!
// if( ie.getMethodRef().resolve().getSubSignature().equals(new String("boolean remove(java.lang.Object)")) )
// {
// G.v().out.println("*!*!*!*!*! has FLOW SENSITIVE infoFlowGraph: ");
// ClassInfoFlowAnalysis.printDataFlowGraph(infoFlowGraph);
// }
List returnValueSources = new ArrayList();
Iterator