package jqian.sootex.ptsto; import java.util.*; import jqian.sootex.location.*; import soot.*; import soot.jimple.spark.pag.*; import soot.jimple.spark.sets.*; import soot.util.*; /** * Query points-to relations using spark framework. * Spark assumes all pointer can points to null which is not explicitly shown. */ public class SparkPtsToQuery implements IPtsToQuery{ private final InstanceObject[] _alloc2obj; private AllocNode[] _obj2alloc; public SparkPtsToQuery(){ PAG _pa = (PAG)Scene.v().getPointsToAnalysis(); int allocNum = _pa.getNumAllocNodes(); _alloc2obj = new InstanceObject[allocNum+1]; _obj2alloc = new AllocNode[allocNum*2]; //maybe not enough ArrayNumberer numberer=_pa.getAllocNodeNumberer(); //FIX 2007-06-20 "i<allocNum" => "i<=allocNum" for(int i=1;i<=allocNum;i++){//0 - null pointer AllocNode node=(AllocNode)numberer.get(i); InstanceObject loc= InstanceObject.makeInstObject(node); _alloc2obj[i]=loc; if(loc!=null){ setHeapObj2NodeMap(loc,node); } } } private final void setHeapObj2NodeMap(final InstanceObject hObj,final AllocNode node){ int hId=hObj.getNumber(); if(hId >= _obj2alloc.length-1){ int oldSz = _obj2alloc.length; int newSz = oldSz * 2; while(hId >= newSz-1){ newSz *= 2; } AllocNode[] tmp = new AllocNode[newSz]; for (int i = 0; i < oldSz; i++) { tmp[i] = _obj2alloc[i]; } _obj2alloc=tmp; } _obj2alloc[hId]=node; } private final PointsToSet getPointTos(final Location ptr){ PAG pa = (PAG)Scene.v().getPointsToAnalysis(); PointsToSet result = null; try{ if(ptr instanceof StackLocation){ Value v = ((StackLocation)ptr).getValue(); assert(v instanceof Local); result = pa.reachingObjects((Local)v); } else if(ptr instanceof GlobalLocation){ SootField field = ((GlobalLocation)ptr).getSootField(); result = pa.reachingObjects(field); } else if(ptr instanceof HeapLocation){ InstanceObject hobj = ((HeapLocation)ptr).getWrapperObject(); AllocNode node= _obj2alloc[hobj.getNumber()]; AllocDotField field=null; if(ptr instanceof ArrayElmt){ field=node.dot(ArrayElement.v()); } else if(ptr instanceof HeapField){ field=node.dot(((HeapField)ptr).getField()); } if(field!=null) result = field.getP2Set(); } } catch(Exception e){ pa.hashCode(); } return result; } private static final int CACHE_SIZE = 11; private final Location[] cachedLocs = new Location[CACHE_SIZE]; @SuppressWarnings("unchecked") private final Set<InstanceObject>[] cachedPtsTos = new Set[CACHE_SIZE]; private int cacheTail = 0; public Set<InstanceObject> getPointTos(SootMethod m, final Unit stmt, final Location ptr){ if(!ptr.isPointer()) return Collections.emptySet(); // search in cache for(int i=0; i<CACHE_SIZE; i++){ if(cachedLocs[i]==ptr){ return cachedPtsTos[i]; } } Set<InstanceObject> pt2Set = new HashSet<InstanceObject>(); if(ptr instanceof MethodRet){ //collect points-to information from return pointers MethodRet retPtr = (MethodRet)ptr; Collection<Location> sources = retPtr.getValueSource(); for(Location loc: sources){ if(loc!=null){ Set<InstanceObject> s = getPointTos(m, stmt,loc); pt2Set.addAll(s); } } } else{ PointsToSet p2St = getPointTos(ptr); if(p2St!=null) pt2SetToHeapObjSet(p2St,pt2Set); //else // pt2Set.add(Location.UNKNOWN); } // update cache cachedLocs[cacheTail] = ptr; cachedPtsTos[cacheTail] = pt2Set; cacheTail = (cacheTail+1)%CACHE_SIZE; return pt2Set; } ////////////////////// Private part /////////////////////////////////////// private final class PtSetVisitor extends P2SetVisitor{ final Set<InstanceObject> _hset; public PtSetVisitor(final Set<InstanceObject> hSet){ this._hset=hSet; } public void visit(final Node n) { assert(n instanceof AllocNode); InstanceObject obj=_alloc2obj[n.getNumber()]; if(obj!=null) _hset.add(obj); } public boolean getReturnValue(){ return true; } } private final void pt2SetToHeapObjSet(final PointsToSet ptSt,final Set<InstanceObject> out){ if(ptSt instanceof PointsToSetInternal){ PointsToSetInternal ptStInternal=(PointsToSetInternal)ptSt; PtSetVisitor visitor = new PtSetVisitor(out); ptStInternal.forall(visitor); } else{ throw new RuntimeException("Unsupported type: "+ptSt.getClass()); } } }