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<EquivalentValue> sources = sourcesOf(node); Iterator<EquivalentValue> sourcesIt = sources.iterator(); while(sourcesIt.hasNext()) { EquivalentValue source = sourcesIt.next(); if(source.getValue() instanceof Ref) { infoFlowSummary.addEdge(source, node); } } } } public List<EquivalentValue> sourcesOf(EquivalentValue node) { return sourcesOf(node, new HashSet<EquivalentValue>(), new HashSet<EquivalentValue>()); } private List<EquivalentValue> sourcesOf(EquivalentValue node, Set<EquivalentValue> visitedSources, Set<EquivalentValue> visitedSinks) { visitedSources.add(node); List<EquivalentValue> ret = new LinkedList<EquivalentValue>(); 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<EquivalentValue> sinks = sinksOf(node, visitedSources, visitedSinks); Iterator<EquivalentValue> 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<EquivalentValue> sinksOf(EquivalentValue node) { return sinksOf(node, new HashSet<EquivalentValue>(), new HashSet<EquivalentValue>()); } private List<EquivalentValue> sinksOf(EquivalentValue node, Set<EquivalentValue> visitedSources, Set<EquivalentValue> visitedSinks) { List<EquivalentValue> ret = new LinkedList<EquivalentValue>(); // 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<EquivalentValue> 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 <Immediate> // if the node is a static field // source = node <StaticFieldRef> // if the node is a field // source = receiver object <Local> // 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("*!*!*!*!*!<boolean remove(java.lang.Object)> has FLOW SENSITIVE infoFlowSummary: "); // ClassInfoFlowAnalysis.printDataFlowGraph(infoFlowSummary); // } List returnValueSources = new ArrayList(); Iterator<Object> nodeIt = dataFlowSummary.getNodes().iterator(); while(nodeIt.hasNext()) { EquivalentValue nodeEqVal = (EquivalentValue) nodeIt.next(); if(!(nodeEqVal.getValue() instanceof Ref)) throw new RuntimeException("Illegal node type in data flow summary:" + nodeEqVal.getValue() + " should be an object of type Ref."); Ref node = (Ref) nodeEqVal.getValue(); List sources = new ArrayList(); // Value source = null; if(node instanceof ParameterRef) { ParameterRef param = (ParameterRef) node; if(param.getIndex() == -1) continue; sources.add(ie.getArg(param.getIndex())); // source = ; // Immediate } else if(node instanceof StaticFieldRef) { sources.add(node); // source = node; // StaticFieldRef } else if(node instanceof InstanceFieldRef && ie instanceof InstanceInvokeExpr) { InstanceInvokeExpr iie = (InstanceInvokeExpr) ie; if(iie.getBase() == thisLocal) { sources.add(node); // source = node; } else if(includeInnerFields) { if( false ) // isNonRefType(node.getType()) ) // TODO: double check this policy { // primitives flow from the parent object InstanceFieldRef ifr = (InstanceFieldRef) node; if(ifr.getBase() instanceof FakeJimpleLocal)// && ((FakeJimpleLocal) ifr.getBase()).getRealLocal() != null) ; // sources.add(((FakeJimpleLocal) ifr.getBase()).getRealLocal()); else sources.add(ifr.getBase()); } else { // objects flow from both InstanceFieldRef ifr = (InstanceFieldRef) node; if(ifr.getBase() instanceof FakeJimpleLocal)// && ((FakeJimpleLocal) ifr.getBase()).getRealLocal() != null) ; // sources.add(((FakeJimpleLocal) ifr.getBase()).getRealLocal()); else sources.add(ifr.getBase()); sources.add(node); } // source = node; // handleInnerField(source); } else { sources.add(iie.getBase()); // source = iie.getBase(); // Local } } else if(node instanceof InstanceFieldRef && includeInnerFields) { if( false ) // isNonRefType(node.getType()) ) // TODO: double check this policy { // primitives flow from the parent object InstanceFieldRef ifr = (InstanceFieldRef) node; if(ifr.getBase() instanceof FakeJimpleLocal)// && ((FakeJimpleLocal) ifr.getBase()).getRealLocal() != null) ; // sources.add(((FakeJimpleLocal) ifr.getBase()).getRealLocal()); else sources.add(ifr.getBase()); } else { // objects flow from both InstanceFieldRef ifr = (InstanceFieldRef) node; if(ifr.getBase() instanceof FakeJimpleLocal)// && ((FakeJimpleLocal) ifr.getBase()).getRealLocal() != null) ; // sources.add(((FakeJimpleLocal) ifr.getBase()).getRealLocal()); else sources.add(ifr.getBase()); sources.add(node); } // source = node; // handleInnerField(source); } else if(node instanceof ThisRef && ie instanceof InstanceInvokeExpr) { InstanceInvokeExpr iie = (InstanceInvokeExpr) ie; sources.add(iie.getBase()); // source = iie.getBase(); // Local } else { throw new RuntimeException("Unknown Node Type in Data Flow Graph: node " + node + " in InvokeExpr " + ie); } Iterator sinksIt = dataFlowSummary.getSuccsOfAsSet(nodeEqVal).iterator(); while(sinksIt.hasNext()) { EquivalentValue sinkEqVal = (EquivalentValue) sinksIt.next(); Ref sink = (Ref) sinkEqVal.getValue(); if(sink instanceof ParameterRef) { ParameterRef param = (ParameterRef) sink; if(param.getIndex() == -1) { returnValueSources.addAll(sources); } else { for(Iterator sourcesIt = sources.iterator(); sourcesIt.hasNext(); ) { Value source = (Value) sourcesIt.next(); handleFlowsToDataStructure(ie.getArg(param.getIndex()), source); } } } else if(sink instanceof StaticFieldRef) { for(Iterator sourcesIt = sources.iterator(); sourcesIt.hasNext(); ) { Value source = (Value) sourcesIt.next(); handleFlowsToValue(sink, source); } } else if(sink instanceof InstanceFieldRef && ie instanceof InstanceInvokeExpr) { InstanceInvokeExpr iie = (InstanceInvokeExpr) ie; if(iie.getBase() == thisLocal) { for(Iterator sourcesIt = sources.iterator(); sourcesIt.hasNext(); ) { Value source = (Value) sourcesIt.next(); handleFlowsToValue(sink, source); } } else if(includeInnerFields) { for(Iterator sourcesIt = sources.iterator(); sourcesIt.hasNext(); ) { Value source = (Value) sourcesIt.next(); if( false ) // isNonRefType(sink.getType()) ) // TODO: double check this policy { // primitives flow to the parent object InstanceFieldRef ifr = (InstanceFieldRef) sink; if(ifr.getBase() instanceof FakeJimpleLocal)// && ((FakeJimpleLocal) ifr.getBase()).getRealLocal() != null) ; // handleFlowsToDataStructure(((FakeJimpleLocal) ifr.getBase()).getRealLocal(), source); else handleFlowsToDataStructure(ifr.getBase(), source); } else { // objects flow to the field handleFlowsToValue(sink, source); } handleInnerField(sink); } } else { for(Iterator sourcesIt = sources.iterator(); sourcesIt.hasNext(); ) { Value source = (Value) sourcesIt.next(); handleFlowsToDataStructure(iie.getBase(), source); } } } else if(sink instanceof InstanceFieldRef && includeInnerFields) { for(Iterator sourcesIt = sources.iterator(); sourcesIt.hasNext(); ) { Value source = (Value) sourcesIt.next(); if( false ) // isNonRefType(sink.getType()) ) // TODO: double check this policy { // primitives flow to the parent object InstanceFieldRef ifr = (InstanceFieldRef) sink; if(ifr.getBase() instanceof FakeJimpleLocal)// && ((FakeJimpleLocal) ifr.getBase()).getRealLocal() != null) ; // handleFlowsToDataStructure(((FakeJimpleLocal) ifr.getBase()).getRealLocal(), source); else handleFlowsToDataStructure(ifr.getBase(), source); } else { handleFlowsToValue(sink, source); } handleInnerField(sink); } } } } // return the list of return value sources return returnValueSources; } protected void addFlowToCdfg(Stmt stmt) { if(stmt instanceof IdentityStmt) // assigns an IdentityRef to a Local { IdentityStmt is = (IdentityStmt) stmt; IdentityRef ir = (IdentityRef) is.getRightOp(); if(ir instanceof JCaughtExceptionRef) { // TODO: What the heck do we do with this??? } else if(ir instanceof ParameterRef) { if( !ignoreThisDataType(ir.getType()) ) { // <Local, ParameterRef and sources> handleFlowsToValue(is.getLeftOp(), ir); } } else if(ir instanceof ThisRef) { if( !ignoreThisDataType(ir.getType()) ) { // <Local, ThisRef and sources> handleFlowsToValue(is.getLeftOp(), ir); } } } else if(stmt instanceof ReturnStmt) // assigns an Immediate to the "returnRef" { ReturnStmt rs = (ReturnStmt) stmt; Value rv = rs.getOp(); if(rv instanceof Constant) { // No (interesting) data flow } else if(rv instanceof Local) { if( !ignoreThisDataType(rv.getType()) ) { // <ReturnRef, sources of Local> handleFlowsToValue(returnRef, rv); } } } else if(stmt instanceof AssignStmt) // assigns a Value to a Variable { AssignStmt as = (AssignStmt) stmt; Value lv = as.getLeftOp(); Value rv = as.getRightOp(); Value sink = null; boolean flowsToDataStructure = false; if(lv instanceof Local) // data flows into the Local { sink = lv; } else if(lv instanceof ArrayRef) // data flows into the base's data structure { ArrayRef ar = (ArrayRef) lv; sink = ar.getBase(); flowsToDataStructure = true; } else if(lv instanceof StaticFieldRef) // data flows into the field ref { sink = lv; } else if(lv instanceof InstanceFieldRef) { InstanceFieldRef ifr = (InstanceFieldRef) lv; if( ifr.getBase() == thisLocal ) // data flows into the field ref { sink = lv; } else if( includeInnerFields ) { if( false ) //isNonRefType(lv.getType()) ) // TODO: double check this policy { // primitives flow to the parent object sink = ifr.getBase(); flowsToDataStructure = true; } else { // objects flow to the field sink = lv; handleInnerField(sink); } } else // data flows into the base's data structure { sink = ifr.getBase(); flowsToDataStructure = true; } } List sources = new ArrayList(); boolean interestingFlow = true; if(rv instanceof Local) { sources.add(rv); interestingFlow = !ignoreThisDataType(rv.getType()); } else if(rv instanceof Constant) { sources.add(rv); interestingFlow = !ignoreThisDataType(rv.getType()); } else if(rv instanceof ArrayRef) // data flows from the base's data structure { ArrayRef ar = (ArrayRef) rv; sources.add(ar.getBase()); interestingFlow = !ignoreThisDataType(ar.getType()); } else if(rv instanceof StaticFieldRef) { sources.add(rv); interestingFlow = !ignoreThisDataType(rv.getType()); } else if(rv instanceof InstanceFieldRef) { InstanceFieldRef ifr = (InstanceFieldRef) rv; if( ifr.getBase() == thisLocal ) // data flows from the field ref { sources.add(rv); interestingFlow = !ignoreThisDataType(rv.getType()); } else if( includeInnerFields ) { if( false ) // isNonRefType(rv.getType()) ) // TODO: double check this policy { // primitives flow from the parent object sources.add(ifr.getBase()); } else { // objects flow from both sources.add(ifr.getBase()); sources.add(rv); handleInnerField(rv); } interestingFlow = !ignoreThisDataType(rv.getType()); } else // data flows from the base's data structure { sources.add(ifr.getBase()); interestingFlow = !ignoreThisDataType(ifr.getType()); } } else if(rv instanceof AnyNewExpr) { sources.add(rv); interestingFlow = !ignoreThisDataType(rv.getType()); } else if(rv instanceof BinopExpr) // does this include compares and others??? yes { BinopExpr be = (BinopExpr) rv; sources.add(be.getOp1()); sources.add(be.getOp2()); interestingFlow = !ignoreThisDataType(be.getType()); } else if(rv instanceof CastExpr) { CastExpr ce = (CastExpr) rv; sources.add(ce.getOp()); interestingFlow = !ignoreThisDataType(ce.getType()); } else if(rv instanceof InstanceOfExpr) { InstanceOfExpr ioe = (InstanceOfExpr) rv; sources.add(ioe.getOp()); interestingFlow = !ignoreThisDataType(ioe.getType()); } else if(rv instanceof UnopExpr) { UnopExpr ue = (UnopExpr) rv; sources.add(ue.getOp()); interestingFlow = !ignoreThisDataType(ue.getType()); } else if(rv instanceof InvokeExpr) { InvokeExpr ie = (InvokeExpr) rv; sources.addAll(handleInvokeExpr(ie, as)); interestingFlow = !ignoreThisDataType(ie.getType()); } if(interestingFlow) { if(flowsToDataStructure) { Iterator sourcesIt = sources.iterator(); while(sourcesIt.hasNext()) { Value source = (Value) sourcesIt.next(); handleFlowsToDataStructure(sink, source); } } else { Iterator sourcesIt = sources.iterator(); while(sourcesIt.hasNext()) { Value source = (Value) sourcesIt.next(); // if(flowsToBoth && sink instanceof InstanceFieldRef) // handleFlowsToDataStructure(((InstanceFieldRef)sink).getBase(), source); handleFlowsToValue(sink, source); } } } } else if(stmt.containsInvokeExpr()) // flows data between receiver object, parameters, globals, and return value { handleInvokeExpr(stmt.getInvokeExpr(), stmt); } } public Value getThisLocal() { return thisLocal; } }