package jqian.sootex.du; import java.util.*; import jqian.sootex.Cache; import jqian.sootex.location.AccessPath; import jqian.sootex.location.Location; import jqian.sootex.location.GlobalLocation; import jqian.sootex.location.HeapAbstraction; import jqian.sootex.ptsto.IPtsToQuery; import jqian.sootex.ptsto.PtsToHelper; import jqian.sootex.sideeffect.ISideEffectAnalysis; import jqian.sootex.util.CFGEntry; import jqian.sootex.util.CFGExit; import jqian.sootex.util.callgraph.Callees; import soot.*; import soot.jimple.DefinitionStmt; import soot.jimple.IdentityStmt; import soot.jimple.InstanceInvokeExpr; import soot.jimple.InvokeExpr; import soot.jimple.NewArrayExpr; import soot.jimple.NewExpr; import soot.jimple.NewMultiArrayExpr; import soot.jimple.ReturnStmt; import soot.jimple.Stmt; import soot.jimple.toolkits.callgraph.CallGraph; import soot.toolkits.graph.*; /** * A reaching definition analysis implemented with bit vectors. */ public class RDAnalysis extends DUAnalysis{ protected IPtsToQuery _pt2Query; protected HeapAbstraction _heapAbstraction; public RDAnalysis(MethodOrMethodContext mc,DirectedGraph<Unit> graph,IPtsToQuery pt2Query, HeapAbstraction heapAbstraction, ISideEffectAnalysis sideEffect,boolean verbose){ super(mc, graph, sideEffect, verbose); this._pt2Query = pt2Query; this._heapAbstraction = heapAbstraction; } public void build(){ super.build(); _pt2Query = null; } /** ID name of the analysis */ protected String getAnalysisName(){ return "RD"; } /** DEF set at the method entry. */ protected Collection<ReachingDU> getEntryDU(){ Unit entry = CFGEntry.v(); Collection<ReachingDU> entrySet = new ArrayList<ReachingDU>(); // parameters, including the globals Collection<Location> params = collectParams(); for (Location loc : params) { AccessPath ap = AccessPath.getByRoot(loc); entrySet.add(new ReachingDU(entry, ap, loc)); } // for used heap location Collection<Location> use = _sideEffect.getUseHeapLocs(_method); if (use.size() > 0) { entrySet.add(new ReachingDU(entry, null, use)); } return entrySet; } /** collect the reaching definitions generated by a method call. * NOTE: The definition on the return value has already been considered, * this method just needs to collect the definition on global locations */ protected Collection<ReachingDU> collectInvokeDefs(Unit invokeStmt){ Collection<ReachingDU> rdSet = new ArrayList<ReachingDU>(); CallGraph cg = Scene.v().getCallGraph(); Callees callees = new Callees(cg, invokeStmt); // XXX: We do not consider the effects of sub threads here // For multiple thread programs, we need other analysis to find the inter-thread dependences callees.all().removeAll(callees.threads()); // collect definition to globals Set<Location> defGlobals = new HashSet<Location>(); for(SootMethod tgt: callees.all()){ if (!tgt.isConcrete()) continue; Collection<Location> mod = _sideEffect.getModGlobals(tgt); defGlobals.addAll(mod); } for(Location gb: defGlobals){ AccessPath ap = null; if(gb instanceof GlobalLocation){ ap = AccessPath.getByRoot(gb); } ReachingDU gbrd = new ReachingDU(invokeStmt,ap,gb); rdSet.add(gbrd); } // collect definitions to heap location if(callees.all().size()==1){ SootMethod tgt = callees.all().iterator().next(); Collection<Location> defHeaps; if(tgt.isConcrete()){ defHeaps = _sideEffect.getModHeapLocs(tgt); } else{ defHeaps = getNativeCallMod(invokeStmt, tgt); } if(!defHeaps.isEmpty()){ ReachingDU rd = new ReachingDU(invokeStmt,null,defHeaps); rdSet.add(rd); } } else{ Set<Location> defHeaps = new HashSet<Location>(); for(SootMethod tgt: callees.all()){ Collection<Location> mod; if (tgt.isConcrete()){ mod = _sideEffect.getModHeapLocs(tgt); } else{ mod = getNativeCallMod(invokeStmt, tgt); } defHeaps.addAll(mod); } if(!defHeaps.isEmpty()){ ReachingDU rd = new ReachingDU(invokeStmt,null,defHeaps); rdSet.add(rd); } } return rdSet; } @SuppressWarnings("unchecked") private Collection<Location> getNativeCallMod(Unit u, SootMethod tgt){ InvokeExpr invoke = ((Stmt)u).getInvokeExpr(); Value receiver = null; if(!invoke.getMethod().isStatic()){ InstanceInvokeExpr iie = (InstanceInvokeExpr)invoke; receiver = iie.getBase(); } Collection<AccessPath> def = NativeMethodDUHelper.v().getDef(tgt, receiver, invoke.getArgs()); if(def.size()==0){ return Collections.emptyList(); } else if(def.size()==1){ AccessPath d = def.iterator().next(); Collection<Location> defLocs = PtsToHelper.getAccessedLocations(_pt2Query, _heapAbstraction, u, d); return defLocs; } else{ Collection<Location> locs = new HashSet<Location>(); for(AccessPath d: def){ Collection<Location> defLocs = PtsToHelper.getAccessedLocations(_pt2Query, _heapAbstraction, u, d); locs.addAll(defLocs); } return locs; } } /** Collect RD of each statement */ protected Collection<ReachingDU> collectStmtDU(Unit u){ if(u==CFGEntry.v()){ return getEntryDU(); } if(u==CFGExit.v() || u instanceof IdentityStmt || !(u instanceof Stmt)){ return Collections.emptyList(); } Collection<ReachingDU> rdSet = new ArrayList<ReachingDU>(); Stmt s = (Stmt)u; for(Object box: s.getDefBoxes()){ Value v = ((ValueBox)box).getValue(); AccessPath def = AccessPath.valueToAccessPath(_method, s, v); ReachingDU rd; if (def.length() == 0) { rd = new ReachingDU(u, def, def.getRoot()); } else { Collection<Location> defLocs = PtsToHelper.getAccessedLocations(_pt2Query, _heapAbstraction, u, def); rd = new ReachingDU(u, def, defLocs); } rdSet.add(rd); } //each new expression will generate a couple of assignments initializing the fields to their default value if(s instanceof DefinitionStmt){ DefinitionStmt ds = (DefinitionStmt)s; Value leftOp = ds.getLeftOp(); Value rightOp = ds.getRightOp(); if(rightOp instanceof NewExpr){ AccessPath left = AccessPath.valueToAccessPath(_method, s, leftOp); RefType type = (RefType)rightOp.getType(); SootClass cls = type.getSootClass(); Collection<SootField> fields = Cache.v().getAllInstanceFields(cls); for(SootField f: fields){ AccessPath ap = left.appendFieldRef(f); Collection<Location> defLocs = PtsToHelper.getAccessedLocations(_pt2Query, _heapAbstraction, u, ap); ReachingDU rd = new ReachingDU(u,ap,defLocs); rdSet.add(rd); } } else if(rightOp instanceof NewArrayExpr || rightOp instanceof NewMultiArrayExpr){ AccessPath left = AccessPath.valueToAccessPath(_method, s, leftOp); AccessPath ap = left.appendArrayRef(); Collection<Location> defLocs = PtsToHelper.getAccessedLocations(_pt2Query, _heapAbstraction, u, ap); ReachingDU rd = new ReachingDU(u,ap,defLocs); rdSet.add(rd); } } else if(s instanceof ReturnStmt){ // treat return as a definition to a unique return value Location ret = Location.methodToRet(_method); AccessPath def = AccessPath.getByRoot(ret); ReachingDU rd = new ReachingDU(u, def, ret); rdSet.add(rd); } //if there exits a method call if(s.containsInvokeExpr()){ Collection<ReachingDU> rds = collectInvokeDefs(u); rdSet.addAll(rds); } return rdSet; } }