All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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