
soot.jimple.toolkits.infoflow.SmartMethodInfoFlowAnalysis Maven / Gradle / Ivy
package soot.jimple.toolkits.infoflow;
import soot.*;
import java.util.*;
import soot.toolkits.graph.*;
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 SmartMethodInfoFlowAnalysis
{
UnitGraph graph;
SootMethod sm;
Value thisLocal;
InfoFlowAnalysis dfa;
boolean refOnly; // determines if primitive type data flow is included
boolean includeInnerFields; // determines if flow to a field of an object (other than this) is treated like flow to that object
HashMutableDirectedGraph abbreviatedInfoFlowGraph;
HashMutableDirectedGraph infoFlowSummary;
Ref returnRef;
boolean printMessages;
public static int counter = 0;
public SmartMethodInfoFlowAnalysis(UnitGraph g, InfoFlowAnalysis dfa)
{
graph = g;
this.sm = g.getBody().getMethod();
if(sm.isStatic())
this.thisLocal = null;
else
this.thisLocal = g.getBody().getThisLocal();
this.dfa = dfa;
this.refOnly = !dfa.includesPrimitiveInfoFlow();
this.includeInnerFields = dfa.includesInnerFields();
this.abbreviatedInfoFlowGraph = new MemoryEfficientGraph();
this.infoFlowSummary = 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; //dfa.printDebug();
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(!infoFlowSummary.containsNode(parameterRefEqVal))
infoFlowSummary.addNode(parameterRefEqVal);
}
// Add every relevant field of this class (static methods don't get non-static fields)
for(Iterator it = sm.getDeclaringClass().getFields().iterator(); it.hasNext(); )
{
SootField sf = (SootField) it.next();
if(sf.isStatic() || !sm.isStatic())
{
EquivalentValue fieldRefEqVal;
if(!sm.isStatic())
fieldRefEqVal = InfoFlowAnalysis.getNodeForFieldRef(sm, sf, sm.retrieveActiveBody().getThisLocal());
else
fieldRefEqVal = InfoFlowAnalysis.getNodeForFieldRef(sm, sf);
if(!infoFlowSummary.containsNode(fieldRefEqVal))
infoFlowSummary.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();
if(scField.isStatic() || !sm.isStatic())
{
EquivalentValue fieldRefEqVal;
if(!sm.isStatic())
fieldRefEqVal = InfoFlowAnalysis.getNodeForFieldRef(sm, scField, sm.retrieveActiveBody().getThisLocal());
else
fieldRefEqVal = InfoFlowAnalysis.getNodeForFieldRef(sm, scField);
if(!infoFlowSummary.containsNode(fieldRefEqVal))
infoFlowSummary.addNode(fieldRefEqVal);
}
}
superclass = superclass.getSuperclass();
}
// Add thisref of this class
if(!sm.isStatic())
{
EquivalentValue thisRefEqVal = InfoFlowAnalysis.getNodeForThisRef(sm);
if(!infoFlowSummary.containsNode(thisRefEqVal))
infoFlowSummary.addNode(thisRefEqVal);
}
// Add returnref of this method
EquivalentValue returnRefEqVal = new CachedEquivalentValue(returnRef);
if(returnRef.getType() != VoidType.v() && !infoFlowSummary.containsNode(returnRefEqVal))
infoFlowSummary.addNode(returnRefEqVal);
// Do the analysis
Date start = new Date();
int counterSoFar = counter;
if(printMessages)
G.v().out.println("STARTING SMART ANALYSIS FOR " + g.getBody().getMethod() + " -----");
// S=#Statements, R=#Refs, L=#Locals, where generally (S ~= L), (L >> R)
// Generates a data flow graph of refs and locals where "flows to data structure" is represented in a single node
generateAbbreviatedInfoFlowGraph(); // O(S)
// Generates a data flow graph of refs where "flows to data structure" has been resolved
generateInfoFlowSummary(); // O( R*(L+R) )
if(printMessages)
{
long longTime = ((new Date()).getTime() - start.getTime());
float time = (longTime) / 1000.0f;
G.v().out.println("ENDING SMART ANALYSIS FOR " + g.getBody().getMethod() + " ----- " +
(counter - counterSoFar + 1) + " analyses took: " + time + "s");
G.v().out.println(" AbbreviatedDataFlowGraph:");
InfoFlowAnalysis.printInfoFlowSummary(abbreviatedInfoFlowGraph);
G.v().out.println(" DataFlowSummary:");
InfoFlowAnalysis.printInfoFlowSummary(infoFlowSummary);
}
}
public void generateAbbreviatedInfoFlowGraph()
{
Iterator stmtIt = graph.iterator();
while(stmtIt.hasNext())
{
Stmt s = (Stmt) stmtIt.next();
addFlowToCdfg(s);
}
}
public void generateInfoFlowSummary()
{
Iterator nodeIt = infoFlowSummary.iterator();
while(nodeIt.hasNext())
{
EquivalentValue node = (EquivalentValue) nodeIt.next();
List sources = sourcesOf(node);
Iterator sourcesIt = sources.iterator();
while(sourcesIt.hasNext())
{
EquivalentValue source = sourcesIt.next();
if(source.getValue() instanceof Ref)
{
infoFlowSummary.addEdge(source, node);
}
}
}
}
public List sourcesOf(EquivalentValue node) { return sourcesOf(node, new HashSet(), new HashSet()); }
private List sourcesOf(EquivalentValue node, Set visitedSources, Set visitedSinks)
{
visitedSources.add(node);
List ret = new LinkedList();
if(!abbreviatedInfoFlowGraph.containsNode(node))
return ret;
// get direct sources
Set preds = abbreviatedInfoFlowGraph.getPredsOfAsSet(node);
Iterator predsIt = preds.iterator();
while(predsIt.hasNext())
{
EquivalentValue pred = (EquivalentValue) predsIt.next();
if(!visitedSources.contains(pred))
{
ret.add(pred);
ret.addAll(sourcesOf(pred, visitedSources, visitedSinks));
}
}
// get sources of (sources of sinks, of which we are one)
List sinks = sinksOf(node, visitedSources, visitedSinks);
Iterator sinksIt = sinks.iterator();
while(sinksIt.hasNext())
{
EquivalentValue sink = sinksIt.next();
if(!visitedSources.contains(sink))
{
EquivalentValue flowsToSourcesOf = new CachedEquivalentValue(new AbstractDataSource(sink.getValue()));
if( abbreviatedInfoFlowGraph.getPredsOfAsSet(sink).contains(flowsToSourcesOf) )
{
ret.addAll(sourcesOf(flowsToSourcesOf, visitedSources, visitedSinks));
}
}
}
return ret;
}
public List sinksOf(EquivalentValue node) { return sinksOf(node, new HashSet(), new HashSet()); }
private List sinksOf(EquivalentValue node, Set visitedSources, Set visitedSinks)
{
List ret = new LinkedList();
// if(visitedSinks.contains(node))
// return ret;
visitedSinks.add(node);
if(!abbreviatedInfoFlowGraph.containsNode(node))
return ret;
// get direct sinks
Set succs = abbreviatedInfoFlowGraph.getSuccsOfAsSet(node);
Iterator succsIt = succs.iterator();
while(succsIt.hasNext())
{
EquivalentValue succ = (EquivalentValue) succsIt.next();
if(!visitedSinks.contains(succ))
{
ret.add(succ);
ret.addAll(sinksOf(succ, visitedSources, visitedSinks));
}
}
// get sources of (sources of sinks, of which we are one)
succsIt = succs.iterator();
while(succsIt.hasNext())
{
EquivalentValue succ = (EquivalentValue) succsIt.next();
if(succ.getValue() instanceof AbstractDataSource)
{
// It will have ONE successor, who will be the value whose sources it represents
Set vHolder = abbreviatedInfoFlowGraph.getSuccsOfAsSet(succ);
EquivalentValue v = (EquivalentValue) vHolder.iterator().next(); // get the one and only
if(!visitedSinks.contains(v))
{
// Set
ret.addAll(sourcesOf(v, visitedSinks, visitedSinks)); // these nodes are really to be marked as sinks, not sources
}
}
}
return ret;
}
public HashMutableDirectedGraph getMethodInfoFlowSummary()
{
return infoFlowSummary;
}
public HashMutableDirectedGraph getMethodAbbreviatedInfoFlowGraph()
{
return abbreviatedInfoFlowGraph;
}
protected boolean isNonRefType(Type type)
{
return !(type instanceof RefLikeType);
}
protected boolean ignoreThisDataType(Type type)
{
return refOnly && isNonRefType(type);
}
// For when data flows to a local
protected void handleFlowsToValue(Value sink, Value source)
{
EquivalentValue sinkEqVal;
EquivalentValue sourceEqVal;
if(sink instanceof InstanceFieldRef)
{
InstanceFieldRef ifr = (InstanceFieldRef) sink;
sinkEqVal = InfoFlowAnalysis.getNodeForFieldRef(sm, ifr.getField(), (Local) ifr.getBase()); // deals with inner fields
}
else
sinkEqVal = new CachedEquivalentValue(sink);
if(source instanceof InstanceFieldRef)
{
InstanceFieldRef ifr = (InstanceFieldRef) source;
sourceEqVal = InfoFlowAnalysis.getNodeForFieldRef(sm, ifr.getField(), (Local) ifr.getBase()); // deals with inner fields
}
else
sourceEqVal = new CachedEquivalentValue(source);
if( source instanceof Ref && !infoFlowSummary.containsNode(sourceEqVal))
infoFlowSummary.addNode(sourceEqVal);
if( sink instanceof Ref && !infoFlowSummary.containsNode(sinkEqVal))
infoFlowSummary.addNode(sinkEqVal);
if(!abbreviatedInfoFlowGraph.containsNode(sinkEqVal))
abbreviatedInfoFlowGraph.addNode(sinkEqVal);
if(!abbreviatedInfoFlowGraph.containsNode(sourceEqVal))
abbreviatedInfoFlowGraph.addNode(sourceEqVal);
abbreviatedInfoFlowGraph.addEdge(sourceEqVal, sinkEqVal);
}
// for when data flows to the data structure pointed to by a local
protected void handleFlowsToDataStructure(Value base, Value source)
{
EquivalentValue sourcesOfBaseEqVal = new CachedEquivalentValue(new AbstractDataSource(base));
EquivalentValue baseEqVal = new CachedEquivalentValue(base);
EquivalentValue sourceEqVal;
if(source instanceof InstanceFieldRef)
{
InstanceFieldRef ifr = (InstanceFieldRef) source;
sourceEqVal = InfoFlowAnalysis.getNodeForFieldRef(sm, ifr.getField(), (Local) ifr.getBase()); // deals with inner fields
}
else
sourceEqVal = new CachedEquivalentValue(source);
if( source instanceof Ref && !infoFlowSummary.containsNode(sourceEqVal))
infoFlowSummary.addNode(sourceEqVal);
if(!abbreviatedInfoFlowGraph.containsNode(baseEqVal))
abbreviatedInfoFlowGraph.addNode(baseEqVal);
if(!abbreviatedInfoFlowGraph.containsNode(sourceEqVal))
abbreviatedInfoFlowGraph.addNode(sourceEqVal);
if(!abbreviatedInfoFlowGraph.containsNode(sourcesOfBaseEqVal))
abbreviatedInfoFlowGraph.addNode(sourcesOfBaseEqVal);
abbreviatedInfoFlowGraph.addEdge(sourceEqVal, sourcesOfBaseEqVal);
abbreviatedInfoFlowGraph.addEdge(sourcesOfBaseEqVal, baseEqVal); // for convenience
}
// For inner fields... we have base flow to field as a service specifically
// for the sake of LocalObjects... yes, this is a hack!
protected void handleInnerField(Value innerFieldRef)
{
/*
InstanceFieldRef ifr = (InstanceFieldRef) innerFieldRef;
EquivalentValue baseEqVal = new CachedEquivalentValue(ifr.getBase());
EquivalentValue fieldRefEqVal = dfa.getEquivalentValueFieldRef(sm, ifr.getField()); // deals with inner fields
if(!abbreviatedInfoFlowGraph.containsNode(baseEqVal))
abbreviatedInfoFlowGraph.addNode(baseEqVal);
if(!abbreviatedInfoFlowGraph.containsNode(fieldRefEqVal))
abbreviatedInfoFlowGraph.addNode(fieldRefEqVal);
abbreviatedInfoFlowGraph.addEdge(baseEqVal, fieldRefEqVal);
*/
}
// 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)
{
// get the data flow graph
HashMutableDirectedGraph dataFlowSummary = dfa.getInvokeInfoFlowSummary(ie, is, sm); // must return a graph whose nodes are Refs!!!
if(false) // DEBUG!!!
{
SootMethod method = ie.getMethodRef().resolve();
if(method.getDeclaringClass().isApplicationClass())
{
G.v().out.println("Attempting to print graph (will succeed only if ./dfg/ is a valid path)");
MutableDirectedGraph abbreviatedDataFlowGraph = dfa.getInvokeAbbreviatedInfoFlowGraph(ie, sm);
InfoFlowAnalysis.printGraphToDotFile("dfg/" + method.getDeclaringClass().getShortName() + "_" + method.getName() + (refOnly ? "" : "_primitive"),
abbreviatedDataFlowGraph, method.getName() + (refOnly ? "" : "_primitive"), false);
}
}
// if( ie.getMethodRef().resolve().getSubSignature().equals(new String("boolean remove(java.lang.Object)")) )
// {
// G.v().out.println("*!*!*!*!*! has FLOW SENSITIVE infoFlowSummary: ");
// ClassInfoFlowAnalysis.printDataFlowGraph(infoFlowSummary);
// }
List returnValueSources = new ArrayList();
Iterator
© 2015 - 2025 Weber Informatics LLC | Privacy Policy