![JAR search and dependency download from the Maven repository](/logo.png)
soot.jimple.toolkits.infoflow.ClassInfoFlowAnalysis Maven / Gradle / Ivy
package soot.jimple.toolkits.infoflow;
import soot.*;
import java.util.*;
import soot.toolkits.graph.*;
import soot.jimple.*;
// ClassInfoFlowAnalysis written by Richard L. Halpert, 2007-02-22
// Constructs data flow tables for each method of a 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.
public class ClassInfoFlowAnalysis
{
SootClass sootClass;
InfoFlowAnalysis dfa; // used to access the data flow analyses of other classes
Map methodToInfoFlowAnalysis;
Map methodToInfoFlowSummary;
public static int methodCount = 0;
public ClassInfoFlowAnalysis(SootClass sootClass, InfoFlowAnalysis dfa)
{
this.sootClass = sootClass;
this.dfa = dfa;
methodToInfoFlowAnalysis = new HashMap();
methodToInfoFlowSummary = new HashMap();
// doSimpleConservativeDataFlowAnalysis();
}
public SmartMethodInfoFlowAnalysis getMethodInfoFlowAnalysis(SootMethod method)
{
if(!methodToInfoFlowAnalysis.containsKey(method))
{
methodCount++;
// First do simple version that doesn't follow invoke expressions
// The "smart" version will be computed later, but since it may
// request its own DataFlowGraph, we need this simple version first.
if(!methodToInfoFlowSummary.containsKey(method))
{
HashMutableDirectedGraph dataFlowGraph = simpleConservativeInfoFlowAnalysis(method);
methodToInfoFlowSummary.put(method, dataFlowGraph);
}
// Then do smart version that does follow invoke expressions, if possible
if(method.isConcrete())
{
Body b = method.retrieveActiveBody();
UnitGraph g = new ExceptionalUnitGraph(b);
SmartMethodInfoFlowAnalysis smdfa = new SmartMethodInfoFlowAnalysis(g, dfa);
methodToInfoFlowAnalysis.put(method, smdfa);
methodToInfoFlowSummary.remove(method);
methodToInfoFlowSummary.put(method, smdfa.getMethodInfoFlowSummary());
return smdfa;
// G.v().out.println(method + " has SMART infoFlowGraph: ");
// printDataFlowGraph(mdfa.getMethodDataFlowGraph());
}
}
return methodToInfoFlowAnalysis.get(method);
}
public MutableDirectedGraph getMethodInfoFlowSummary(SootMethod method) { return getMethodInfoFlowSummary(method, true); }
public HashMutableDirectedGraph getMethodInfoFlowSummary(SootMethod method, boolean doFullAnalysis)
{
if(!methodToInfoFlowSummary.containsKey(method))
{
methodCount++;
// First do simple version that doesn't follow invoke expressions
// The "smart" version will be computed later, but since it may
// request its own DataFlowGraph, we need this simple version first.
HashMutableDirectedGraph dataFlowGraph = simpleConservativeInfoFlowAnalysis(method);
methodToInfoFlowSummary.put(method, dataFlowGraph);
// Then do smart version that does follow invoke expressions, if possible
if(method.isConcrete() && doFullAnalysis)// && method.getDeclaringClass().isApplicationClass())
{
Body b = method.retrieveActiveBody();
UnitGraph g = new ExceptionalUnitGraph(b);
SmartMethodInfoFlowAnalysis smdfa = new SmartMethodInfoFlowAnalysis(g, dfa);
methodToInfoFlowAnalysis.put(method, smdfa);
methodToInfoFlowSummary.remove(method);
methodToInfoFlowSummary.put(method, smdfa.getMethodInfoFlowSummary());
// G.v().out.println(method + " has SMART infoFlowGraph: ");
// printDataFlowGraph(mdfa.getMethodDataFlowGraph());
}
}
return methodToInfoFlowSummary.get(method);
}
/* public void doFixedPointDataFlowAnalysis()
{
Iterator it = sootClass.getMethods().iterator();
while(it.hasNext())
{
SootMethod method = (SootMethod) it.next();
if(method.isConcrete())
{
Body b = method.retrieveActiveBody();
UnitGraph g = new ExceptionalUnitGraph(b);
SmartMethodInfoFlowAnalysis smdfa = new SmartMethodInfoFlowAnalysis(g, dfa, true);
if(methodToInfoFlowSummary.containsKey(method))
methodToInfoFlowSummary.remove(method);
else
methodCount++;
methodToInfoFlowSummary.put(method, smdfa.getMethodDataFlowSummary());
// G.v().out.println(method + " has FLOW SENSITIVE infoFlowGraph: ");
// printDataFlowGraph(mdfa.getMethodDataFlowGraph());
}
else
{
if(methodToInfoFlowSummary.containsKey(method))
methodToInfoFlowSummary.remove(method);
else
methodCount++;
methodToInfoFlowSummary.put(method, triviallyConservativeDataFlowAnalysis(method));
// G.v().out.println(method + " has TRIVIALLY CONSERVATIVE infoFlowGraph: ");
// printDataFlowGraph((MutableDirectedGraph) methodToInfoFlowSummary.get(method));
}
}
}
//*/
/*
private void doSimpleConservativeDataFlowAnalysis()
{
Iterator it = sootClass.getMethods().iterator();
while(it.hasNext())
{
SootMethod method = (SootMethod) it.next();
MutableDirectedGraph infoFlowGraph = simpleConservativeDataFlowAnalysis(method);
if(methodToInfoFlowSummary.containsKey(method))
methodToInfoFlowSummary.remove(method);
else
methodCount++;
methodToInfoFlowSummary.put(method, infoFlowGraph);
// G.v().out.println(method + " has infoFlowGraph: ");
// printDataFlowGraph(infoFlowGraph);
}
}
//*/
/** Does not require any fixed point calculation */
private HashMutableDirectedGraph simpleConservativeInfoFlowAnalysis(SootMethod sm)
{
// Constructs a graph representing the data flow between fields, parameters, and the
// return value of this method. The graph nodes are EquivalentValue wrapped Refs.
// This version is rather stupid... it just assumes all values flow to all others,
// except for the return value, which is flowed to by all, but flows to none.
// This version is also broken... it can't handle the ThisRef without
// flow sensitivity.
// If this method cannot have a body, then we can't analyze it...
if(!sm.isConcrete())
return triviallyConservativeInfoFlowAnalysis(sm);
Body b = sm.retrieveActiveBody();
UnitGraph g = new ExceptionalUnitGraph(b);
HashSet fieldsStaticsParamsAccessed = new HashSet();
// Get list of fields, globals, and parameters that are accessed
Iterator stmtIt = g.iterator();
while(stmtIt.hasNext())
{
Stmt s = (Stmt) stmtIt.next();
if( s instanceof IdentityStmt )
{
IdentityStmt is = (IdentityStmt) s;
IdentityRef ir = (IdentityRef) is.getRightOp();
if( ir instanceof ParameterRef )
{
ParameterRef pr = (ParameterRef) ir;
fieldsStaticsParamsAccessed.add(InfoFlowAnalysis.getNodeForParameterRef(sm, pr.getIndex()));
}
}
if(s.containsFieldRef())
{
FieldRef ref = s.getFieldRef();
if( ref instanceof StaticFieldRef )
{
// This should be added to the list of fields accessed
// static fields "belong to everyone"
StaticFieldRef sfr = (StaticFieldRef) ref;
fieldsStaticsParamsAccessed.add(InfoFlowAnalysis.getNodeForFieldRef(sm, sfr.getField()));
}
else if( ref instanceof InstanceFieldRef )
{
// If this field is a field of this class,
// then this should be added to the list of fields accessed
InstanceFieldRef ifr = (InstanceFieldRef) ref;
Value base = ifr.getBase();
if(base instanceof Local)
{
if( dfa.includesInnerFields() || ((!sm.isStatic()) && base.equivTo(b.getThisLocal())) )
fieldsStaticsParamsAccessed.add(InfoFlowAnalysis.getNodeForFieldRef(sm, ifr.getField()));
}
}
}
}
// Each accessed field, global, and parameter becomes a node in the graph
HashMutableDirectedGraph dataFlowGraph = new MemoryEfficientGraph();
Iterator accessedIt1 = fieldsStaticsParamsAccessed.iterator();
while(accessedIt1.hasNext())
{
Object o = accessedIt1.next();
dataFlowGraph.addNode(o);
}
// 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(!dataFlowGraph.containsNode(parameterRefEqVal))
dataFlowGraph.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 = InfoFlowAnalysis.getNodeForFieldRef(sm, sf);
if(!dataFlowGraph.containsNode(fieldRefEqVal))
dataFlowGraph.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 = InfoFlowAnalysis.getNodeForFieldRef(sm, scField);
if(!dataFlowGraph.containsNode(fieldRefEqVal))
dataFlowGraph.addNode(fieldRefEqVal);
}
}
superclass = superclass.getSuperclass();
}
// The return value also becomes a node in the graph
ParameterRef returnValueRef = null;
if(sm.getReturnType() != VoidType.v())
{
returnValueRef = new ParameterRef(sm.getReturnType(), -1);
dataFlowGraph.addNode(InfoFlowAnalysis.getNodeForReturnRef(sm));
}
// ThisRef thisRef = null;
if(!sm.isStatic())
{
// thisRef = new ThisRef(sootClass.getType());
dataFlowGraph.addNode(InfoFlowAnalysis.getNodeForThisRef(sm));
fieldsStaticsParamsAccessed.add(InfoFlowAnalysis.getNodeForThisRef(sm));
}
// Create an edge from each node (except the return value) to every other node (including the return value)
// non-Ref-type nodes are ignored
accessedIt1 = fieldsStaticsParamsAccessed.iterator();
while(accessedIt1.hasNext())
{
Object r = accessedIt1.next();
Ref rRef = (Ref) ((EquivalentValue) r).getValue();
if( !(rRef.getType() instanceof RefLikeType) && !dfa.includesPrimitiveInfoFlow())
continue;
Iterator accessedIt2 = fieldsStaticsParamsAccessed.iterator();
while(accessedIt2.hasNext())
{
Object s = accessedIt2.next();
Ref sRef = (Ref) ((EquivalentValue) s).getValue();
if( rRef instanceof ThisRef && sRef instanceof InstanceFieldRef )
; // don't add this edge
else if( sRef instanceof ThisRef && rRef instanceof InstanceFieldRef )
; // don't add this edge
else if( sRef instanceof ParameterRef && dfa.includesInnerFields())
; // don't add edges to parameters if we are including inner fields
else if( sRef.getType() instanceof RefLikeType )
dataFlowGraph.addEdge(r, s);
}
if( returnValueRef != null && (returnValueRef.getType() instanceof RefLikeType || dfa.includesPrimitiveInfoFlow()))
dataFlowGraph.addEdge(r, InfoFlowAnalysis.getNodeForReturnRef(sm));
}
return dataFlowGraph;
}
/** Does not require the method to have a body */
public HashMutableDirectedGraph triviallyConservativeInfoFlowAnalysis(SootMethod sm)
{
HashSet fieldsStaticsParamsAccessed = new HashSet();
// 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);
fieldsStaticsParamsAccessed.add(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 = InfoFlowAnalysis.getNodeForFieldRef(sm, sf);
fieldsStaticsParamsAccessed.add(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 = InfoFlowAnalysis.getNodeForFieldRef(sm, scField);
fieldsStaticsParamsAccessed.add(fieldRefEqVal);
}
}
superclass = superclass.getSuperclass();
}
// Don't add any static fields outside of the class... unsafe???
// Each field, global, and parameter becomes a node in the graph
HashMutableDirectedGraph dataFlowGraph = new MemoryEfficientGraph();
Iterator accessedIt1 = fieldsStaticsParamsAccessed.iterator();
while(accessedIt1.hasNext())
{
Object o = accessedIt1.next();
dataFlowGraph.addNode(o);
}
// The return value also becomes a node in the graph
ParameterRef returnValueRef = null;
if(sm.getReturnType() != VoidType.v())
{
returnValueRef = new ParameterRef(sm.getReturnType(), -1);
dataFlowGraph.addNode(InfoFlowAnalysis.getNodeForReturnRef(sm));
}
ThisRef thisRef = null;
if(!sm.isStatic())
{
thisRef = new ThisRef(sootClass.getType());
dataFlowGraph.addNode(InfoFlowAnalysis.getNodeForThisRef(sm));
fieldsStaticsParamsAccessed.add(InfoFlowAnalysis.getNodeForThisRef(sm));
}
// Create an edge from each node (except the return value) to every other node (including the return value)
// non-Ref-type nodes are ignored
accessedIt1 = fieldsStaticsParamsAccessed.iterator();
while(accessedIt1.hasNext())
{
Object r = accessedIt1.next();
Ref rRef = (Ref) ((EquivalentValue) r).getValue();
if( !(rRef.getType() instanceof RefLikeType) && !dfa.includesPrimitiveInfoFlow() )
continue;
Iterator accessedIt2 = fieldsStaticsParamsAccessed.iterator();
while(accessedIt2.hasNext())
{
Object s = accessedIt2.next();
Ref sRef = (Ref) ((EquivalentValue) s).getValue();
if( rRef instanceof ThisRef && sRef instanceof InstanceFieldRef )
; // don't add this edge
else if( sRef instanceof ThisRef && rRef instanceof InstanceFieldRef )
; // don't add this edge
else if( sRef.getType() instanceof RefLikeType )
dataFlowGraph.addEdge(r, s);
}
if( returnValueRef != null && (returnValueRef.getType() instanceof RefLikeType || dfa.includesPrimitiveInfoFlow()) )
dataFlowGraph.addEdge(r, InfoFlowAnalysis.getNodeForReturnRef(sm));
}
return dataFlowGraph;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy