Package soot.jimple.spark.pag

Source Code of soot.jimple.spark.pag.PAG

/* Soot - a J*va Optimization Framework
* Copyright (C) 2002 Ondrej Lhotak
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/

package soot.jimple.spark.pag;
import java.util.*;

import soot.jimple.*;
import soot.*;
import soot.jimple.spark.sets.*;
import soot.jimple.spark.solver.OnFlyCallGraph;
import soot.jimple.spark.internal.*;
import soot.jimple.spark.builder.*;
import soot.jimple.toolkits.callgraph.Edge;
import soot.jimple.toolkits.pointer.util.NativeMethodDriver;
import soot.util.*;
import soot.util.queue.*;
import soot.options.SparkOptions;
import soot.tagkit.*;
import soot.toolkits.scalar.Pair;

/** Pointer assignment graph.
* @author Ondrej Lhotak
*/
public class PAG implements PointsToAnalysis {
    public PAG( final SparkOptions opts ) {
        this.opts = opts;
        if( opts.add_tags() ) {
            nodeToTag = new HashMap<Node, Tag>();
        }
        typeManager = new TypeManager(this);
        if( !opts.ignore_types() ) {
            typeManager.setFastHierarchy( Scene.v().getOrMakeFastHierarchy() );
        }
        switch( opts.set_impl() ) {
            case SparkOptions.set_impl_hash:
                setFactory = HashPointsToSet.getFactory();
                break;
            case SparkOptions.set_impl_hybrid:
                setFactory = HybridPointsToSet.getFactory();
                break;
            case SparkOptions.set_impl_heintze:
              setFactory = SharedHybridSet.getFactory();
              break;
            case SparkOptions.set_impl_sharedlist:
              setFactory = SharedListSet.getFactory();
              break;
            case SparkOptions.set_impl_array:
                setFactory = SortedArraySet.getFactory();
                break;
            case SparkOptions.set_impl_bit:
                setFactory = BitPointsToSet.getFactory();
                break;
            case SparkOptions.set_impl_double:
                P2SetFactory oldF;
                P2SetFactory newF;
                switch( opts.double_set_old() ) {
                    case SparkOptions.double_set_old_hash:
                        oldF = HashPointsToSet.getFactory();
                        break;
                    case SparkOptions.double_set_old_hybrid:
                        oldF = HybridPointsToSet.getFactory();
                        break;
                    case SparkOptions.double_set_old_heintze:
                      oldF = SharedHybridSet.getFactory();
                      break;
                    case SparkOptions.double_set_old_sharedlist:
                      oldF = SharedListSet.getFactory();
                      break;
                    case SparkOptions.double_set_old_array:
                        oldF = SortedArraySet.getFactory();
                        break;
                    case SparkOptions.double_set_old_bit:
                        oldF = BitPointsToSet.getFactory();
                        break;
                    default:
                        throw new RuntimeException();
                }
                switch( opts.double_set_new() ) {
                    case SparkOptions.double_set_new_hash:
                        newF = HashPointsToSet.getFactory();
                        break;
                    case SparkOptions.double_set_new_hybrid:
                        newF = HybridPointsToSet.getFactory();
                        break;
                    case SparkOptions.double_set_new_heintze:
                      newF = SharedHybridSet.getFactory();
                      break;
                    case SparkOptions.double_set_new_sharedlist:
                      newF = SharedListSet.getFactory();
                      break;
                    case SparkOptions.double_set_new_array:
                        newF = SortedArraySet.getFactory();
                        break;
                    case SparkOptions.double_set_new_bit:
                        newF = BitPointsToSet.getFactory();
                        break;
                    default:
                        throw new RuntimeException();
                }
                setFactory = DoublePointsToSet.getFactory( newF, oldF );
                break;
            default:
                throw new RuntimeException();
        }
    }


    /** Returns the set of objects pointed to by variable l. */
    public PointsToSet reachingObjects( Local l ) {
        VarNode n = findLocalVarNode( l );
        if( n == null ) {
            return EmptyPointsToSet.v();
        }
        return n.getP2Set();
    }
   
    /** Returns the set of objects pointed to by variable l in context c. */
    public PointsToSet reachingObjects( Context c, Local l ) {
        VarNode n = findContextVarNode( l, c );
        if( n == null ) {
            return EmptyPointsToSet.v();
        }
        return n.getP2Set();
    }

    /** Returns the set of objects pointed to by static field f. */
    public PointsToSet reachingObjects( SootField f ) {
        if( !f.isStatic() )
            throw new RuntimeException( "The parameter f must be a *static* field." );
        VarNode n = findGlobalVarNode( f );
        if( n == null ) {
            return EmptyPointsToSet.v();
        }
        return n.getP2Set();
    }

    /** Returns the set of objects pointed to by instance field f
     * of the objects in the PointsToSet s. */
    public PointsToSet reachingObjects( PointsToSet s, final SootField f ) {
        if( f.isStatic() )
            throw new RuntimeException( "The parameter f must be an *instance* field." );

        return reachingObjectsInternal( s, f );
    }

    /** Returns the set of objects pointed to by elements of the arrays
     * in the PointsToSet s. */
    public PointsToSet reachingObjectsOfArrayElement( PointsToSet s ) {
        return reachingObjectsInternal( s, ArrayElement.v() );
    }

    private PointsToSet reachingObjectsInternal( PointsToSet s, final SparkField f ) {
        if( getOpts().field_based() || getOpts().vta() ) {
            VarNode n = findGlobalVarNode( f );
            if( n == null ) {
                return EmptyPointsToSet.v();
            }
            return n.getP2Set();
        }
        if( (getOpts()).propagator() == SparkOptions.propagator_alias ) {
            throw new RuntimeException( "The alias edge propagator does not compute points-to information for instance fields! Use a different propagator." );
        }
        PointsToSetInternal bases = (PointsToSetInternal) s;
        final PointsToSetInternal ret = setFactory.newSet(
                (f instanceof SootField) ? ((SootField)f).getType() : null, this );
        bases.forall( new P2SetVisitor() {
        public final void visit( Node n ) {
            Node nDotF = ((AllocNode) n).dot( f );
            if(nDotF != null) ret.addAll( nDotF.getP2Set(), null );
        }} );
        return ret;
    }

    public P2SetFactory getSetFactory() {
        return setFactory;
    }
    public void cleanUpMerges() {
        if( opts.verbose() ) {
            G.v().out.println( "Cleaning up graph for merged nodes" );
        }
        Map[] maps = { simple, alloc, store, load,
            simpleInv, allocInv, storeInv, loadInv };
        for (Map<Object, Object> m : maps) {
            for (Object object : m.keySet()) {
                lookup( m, object );
            }
        }
        somethingMerged = false;
        if( opts.verbose() ) {
            G.v().out.println( "Done cleaning up graph for merged nodes" );
        }
    }
    public boolean doAddSimpleEdge( VarNode from, VarNode to ) {
        return addToMap( simple, from, to ) | addToMap( simpleInv, to, from );
    }

    public boolean doAddStoreEdge( VarNode from, FieldRefNode to ) {
        return addToMap( store, from, to ) | addToMap( storeInv, to, from );
    }

    public boolean doAddLoadEdge( FieldRefNode from, VarNode to ) {
        return addToMap( load, from, to ) | addToMap( loadInv, to, from );
    }

    public boolean doAddAllocEdge( AllocNode from, VarNode to ) {
        return addToMap( alloc, from, to ) | addToMap( allocInv, to, from );
    }

    /** Node uses this to notify PAG that n2 has been merged into n1. */
    void mergedWith( Node n1, Node n2 ) {
        if( n1.equals( n2 ) ) throw new RuntimeException( "oops" );

        somethingMerged = true;
        if( ofcg() != null ) ofcg().mergedWith( n1, n2 );

        Map[] maps = { simple, alloc, store, load,
            simpleInv, allocInv, storeInv, loadInv };
        for (Map<Node, Object> m : maps) {
            if( !m.keySet().contains( n2 ) ) continue;

            Object[] os = { m.get( n1 ), m.get( n2 ) };
            int size1 = getSize(os[0]); int size2 = getSize(os[1]);
            if( size1 == 0 ) {
                if( os[1] != null ) m.put( n1, os[1] );
            } else if( size2 == 0 ) {
                // nothing needed
            } else if( os[0] instanceof HashSet ) {
                if( os[1] instanceof HashSet ) {
                    ((HashSet) os[0]).addAll( (HashSet) os[1] );
                } else {
                    Node[] ar = (Node[]) os[1];
                    for (Node element0 : ar) {
                        ( (HashSet<Node>) os[0] ).add( element0 );
                    }
                }
            } else if( os[1] instanceof HashSet ) {
                Node[] ar = (Node[]) os[0];
                for (Node element0 : ar) {
                    ((HashSet<Node>) os[1]).add( element0 );
                }
                m.put( n1, os[1] );
            } else if( size1*size2 < 1000 ) {
                Node[] a1 = (Node[]) os[0];
                Node[] a2 = (Node[]) os[1];
                Node[] ret = new Node[size1+size2];
                System.arraycopy( a1, 0, ret, 0, a1.length );
                int j = a1.length;
                outer: for (Node rep : a2) {
                    for( int k = 0; k < j; k++ )
                        if( rep == ret[k] ) continue outer;
                    ret[j++] = rep;
                }
                Node[] newArray = new Node[j];
                System.arraycopy( ret, 0, newArray, 0, j );
                m.put( n1, ret = newArray );
            } else {
                HashSet<Node> s = new HashSet<Node>( size1+size2 );
                for (Object o : os) {
                    if( o == null ) continue;
                    if( o instanceof Set ) {
                        s.addAll( (Set) o );
                    } else {
                        Node[] ar = (Node[]) o;
                        for (Node element1 : ar) {
                            s.add( element1 );
                        }
                    }
                }
                m.put( n1, s );
            }
            m.remove( n2 );
        }
    }
    protected final static Node[] EMPTY_NODE_ARRAY = new Node[0];
    protected Node[] lookup( Map<Object, Object> m, Object key ) {
  Object valueList = m.get( key );
  if( valueList == null ) {
      return EMPTY_NODE_ARRAY;
  }
  if( valueList instanceof Set ) {
            try {
      m.put( key, valueList =
        ( (Set) valueList ).toArray( EMPTY_NODE_ARRAY ) );
            } catch( Exception e ) {
                for( Iterator it = ((Set)valueList).iterator(); it.hasNext(); ) {
                    G.v().out.println( ""+it.next() );
                }
                throw new RuntimeException( ""+valueList+e );
            }
  }
  Node[] ret = (Node[]) valueList;
        if( somethingMerged ) {
            for( int i = 0; i < ret.length; i++ ) {
                Node reti = ret[i];
                Node rep = reti.getReplacement();
                if( rep != reti || rep == key ) {
                    Set<Node> s;
                    if( ret.length <= 75 ) {
                        int j = i;
                        outer: for( ; i < ret.length; i++ ) {
                            reti = ret[i];
                            rep = reti.getReplacement();
                            if( rep == key ) continue;
                            for( int k = 0; k < j; k++ )
                                if( rep == ret[k] ) continue outer;
                            ret[j++] = rep;
                        }
                        Node[] newArray = new Node[j];
                        System.arraycopy( ret, 0, newArray, 0, j );
                        m.put( key, ret = newArray );
                    } else {
                        s = new HashSet<Node>( ret.length * 2 );
                        for( int j = 0; j < i; j++ ) s.add( ret[j] );
                        for( int j = i; j < ret.length; j++ ) {
                            rep = ret[j].getReplacement();
                            if( rep != key ) {
                                s.add( rep );
                            }
                        }
                        m.put( key, ret = s.toArray( EMPTY_NODE_ARRAY ) );
                    }
                    break;
                }
            }
        }
  return ret;
    }

    public Node[] simpleLookup( VarNode key )
    { return lookup( simple, key ); }
    public Node[] simpleInvLookup( VarNode key )
    { return lookup( simpleInv, key ); }
    public Node[] loadLookup( FieldRefNode key )
    { return lookup( load, key ); }
    public Node[] loadInvLookup( VarNode key )
    { return lookup( loadInv, key ); }
    public Node[] storeLookup( VarNode key )
    { return lookup( store, key ); }
    public Node[] storeInvLookup( FieldRefNode key )
    { return lookup( storeInv, key ); }
    public Node[] allocLookup( AllocNode key )
    { return lookup( alloc, key ); }
    public Node[] allocInvLookup( VarNode key )
    { return lookup( allocInv, key ); }
    public Set<Object> simpleSources() { return simple.keySet(); }
    public Set<Object> allocSources() { return alloc.keySet(); }
    public Set<Object> storeSources() { return store.keySet(); }
    public Set<Object> loadSources() { return load.keySet(); }
    public Set<Object> simpleInvSources() { return simpleInv.keySet(); }
    public Set<Object> allocInvSources() { return allocInv.keySet(); }
    public Set<Object> storeInvSources() { return storeInv.keySet(); }
    public Set<Object> loadInvSources() { return loadInv.keySet(); }

    public Iterator<Object> simpleSourcesIterator() { return simple.keySet().iterator(); }
    public Iterator<Object> allocSourcesIterator() { return alloc.keySet().iterator(); }
    public Iterator<Object> storeSourcesIterator() { return store.keySet().iterator(); }
    public Iterator<Object> loadSourcesIterator() { return load.keySet().iterator(); }
    public Iterator<Object> simpleInvSourcesIterator() { return simpleInv.keySet().iterator(); }
    public Iterator<Object> allocInvSourcesIterator() { return allocInv.keySet().iterator(); }
    public Iterator<Object> storeInvSourcesIterator() { return storeInv.keySet().iterator(); }
    public Iterator<Object> loadInvSourcesIterator() { return loadInv.keySet().iterator(); }

    static private int getSize( Object set ) {
        if( set instanceof Set ) return ((Set) set).size();
        else if( set == null ) return 0;
        else return ((Object[]) set).length;
    }


    protected P2SetFactory setFactory;
    protected boolean somethingMerged = false;

    /** Returns the set of objects pointed to by instance field f
     * of the objects pointed to by l. */
    public PointsToSet reachingObjects( Local l, SootField f ) {
        return reachingObjects( reachingObjects(l), f );
    }

    /** Returns the set of objects pointed to by instance field f
     * of the objects pointed to by l in context c. */
    public PointsToSet reachingObjects( Context c, Local l, SootField f ) {
        return reachingObjects( reachingObjects(c, l), f );
    }

    private void addNodeTag( Node node, SootMethod m ) {
        if( nodeToTag != null ) {
            Tag tag;
            if( m == null ) {
                tag = new StringTag( node.toString() );
            } else {
                tag = new LinkTag( node.toString(), m, m.getDeclaringClass().getName() );
            }
            nodeToTag.put( node, tag );
        }
    }
    public AllocNode makeAllocNode( Object newExpr, Type type, SootMethod m ) {
        if( opts.types_for_sites() || opts.vta() ) newExpr = type;
  AllocNode ret = valToAllocNode.get( newExpr );
  if( ret == null ) {
      valToAllocNode.put( newExpr, ret = new AllocNode( this, newExpr, type, m ) );
            newAllocNodes.add( ret );
            addNodeTag( ret, m );
  } else if( !( ret.getType().equals( type ) ) ) {
      throw new RuntimeException( "NewExpr "+newExpr+" of type "+type+
        " previously had type "+ret.getType() );
  }
  return ret;
    }
    public AllocNode makeStringConstantNode( String s ) {
        if( opts.types_for_sites() || opts.vta() )
            return makeAllocNode( RefType.v( "java.lang.String" ),
                    RefType.v( "java.lang.String" ), null );
        StringConstantNode ret = (StringConstantNode) valToAllocNode.get( s );
  if( ret == null ) {
      valToAllocNode.put( s, ret = new StringConstantNode( this, s ) );
            newAllocNodes.add( ret );
            addNodeTag( ret, null );
  }
  return ret;
    }
    public AllocNode makeClassConstantNode( ClassConstant cc ) {
        if( opts.types_for_sites() || opts.vta() )
            return makeAllocNode( RefType.v( "java.lang.Class" ),
                    RefType.v( "java.lang.Class" ), null );
        ClassConstantNode ret = (ClassConstantNode) valToAllocNode.get(cc);
  if( ret == null ) {
      valToAllocNode.put(cc, ret = new ClassConstantNode(this, cc));
            newAllocNodes.add( ret );
            addNodeTag( ret, null );
  }
  return ret;
    }

    ChunkedQueue newAllocNodes = new ChunkedQueue();
    public QueueReader allocNodeListener() { return newAllocNodes.reader(); }

    /** Finds the GlobalVarNode for the variable value, or returns null. */
    public GlobalVarNode findGlobalVarNode( Object value ) {
        if( opts.rta() ) {
            value = null;
        }
  return valToGlobalVarNode.get( value );
    }
    /** Finds the LocalVarNode for the variable value, or returns null. */
    public LocalVarNode findLocalVarNode( Object value ) {
        if( opts.rta() ) {
            value = null;
        } else if( value instanceof Local ) {
            return (LocalVarNode) localToNodeMap.get( (Local) value );
        }
  return valToLocalVarNode.get( value );
    }
    /** Finds or creates the GlobalVarNode for the variable value, of type type. */
    public GlobalVarNode makeGlobalVarNode( Object value, Type type ) {
        if( opts.rta() ) {
            value = null;
            type = RefType.v("java.lang.Object");
        }
        GlobalVarNode ret = valToGlobalVarNode.get( value );
        if( ret == null ) {
            valToGlobalVarNode.put( value,
                    ret = new GlobalVarNode( this, value, type ) );
            addNodeTag( ret, null );
        } else if( !( ret.getType().equals( type ) ) ) {
            throw new RuntimeException( "Value "+value+" of type "+type+
                    " previously had type "+ret.getType() );
        }
  return ret;
    }
    /** Finds or creates the LocalVarNode for the variable value, of type type. */
    public LocalVarNode makeLocalVarNode( Object value, Type type, SootMethod method ) {
        if( opts.rta() ) {
            value = null;
            type = RefType.v("java.lang.Object");
            method = null;
        } else if( value instanceof Local ) {
            Local val = (Local) value;
            if( val.getNumber() == 0 ) Scene.v().getLocalNumberer().add(val);
            LocalVarNode ret = (LocalVarNode) localToNodeMap.get( val );
            if( ret == null ) {
                localToNodeMap.put( (Local) value,
                    ret = new LocalVarNode( this, value, type, method ) );
                addNodeTag( ret, method );
            } else if( !( ret.getType().equals( type ) ) ) {
                throw new RuntimeException( "Value "+value+" of type "+type+
                        " previously had type "+ret.getType() );
            }
            return ret;
        }
        LocalVarNode ret = valToLocalVarNode.get( value );
        if( ret == null ) {
            valToLocalVarNode.put( value,
                    ret = new LocalVarNode( this, value, type, method ) );
            addNodeTag( ret, method );
        } else if( !( ret.getType().equals( type ) ) ) {
            throw new RuntimeException( "Value "+value+" of type "+type+
                    " previously had type "+ret.getType() );
        }
  return ret;
    }
    /** Finds the ContextVarNode for base variable value and context
     * context, or returns null. */
    public ContextVarNode findContextVarNode( Object baseValue, Context context ) {
  LocalVarNode base = findLocalVarNode( baseValue );
  if( base == null ) return null;
  return base.context( context );
    }
    /** Finds or creates the ContextVarNode for base variable baseValue and context
     * context, of type type. */
    public ContextVarNode makeContextVarNode( Object baseValue, Type baseType,
      Context context, SootMethod method ) {
  LocalVarNode base = makeLocalVarNode( baseValue, baseType, method );
        return makeContextVarNode( base, context );
    }
    /** Finds or creates the ContextVarNode for base variable base and context
     * context, of type type. */
    public ContextVarNode makeContextVarNode( LocalVarNode base, Context context ) {
  ContextVarNode ret = base.context( context );
  if( ret == null ) {
      ret = new ContextVarNode( this, base, context );
            addNodeTag( ret, base.getMethod() );
  }
  return ret;
    }
    /** Finds the FieldRefNode for base variable value and field
     * field, or returns null. */
    public FieldRefNode findLocalFieldRefNode( Object baseValue, SparkField field ) {
  VarNode base = findLocalVarNode( baseValue );
  if( base == null ) return null;
  return base.dot( field );
    }
    /** Finds the FieldRefNode for base variable value and field
     * field, or returns null. */
    public FieldRefNode findGlobalFieldRefNode( Object baseValue, SparkField field ) {
  VarNode base = findGlobalVarNode( baseValue );
  if( base == null ) return null;
  return base.dot( field );
    }
    /** Finds or creates the FieldRefNode for base variable baseValue and field
     * field, of type type. */
    public FieldRefNode makeLocalFieldRefNode( Object baseValue, Type baseType,
      SparkField field, SootMethod method ) {
  VarNode base = makeLocalVarNode( baseValue, baseType, method );
        return makeFieldRefNode( base, field );
    }
    /** Finds or creates the FieldRefNode for base variable baseValue and field
     * field, of type type. */
    public FieldRefNode makeGlobalFieldRefNode( Object baseValue, Type baseType,
      SparkField field ) {
  VarNode base = makeGlobalVarNode( baseValue, baseType );
        return makeFieldRefNode( base, field );
    }
    /** Finds or creates the FieldRefNode for base variable base and field
     * field, of type type. */
    public FieldRefNode makeFieldRefNode( VarNode base, SparkField field ) {
  FieldRefNode ret = base.dot( field );
  if( ret == null ) {
      ret = new FieldRefNode( this, base, field );
      if( base instanceof LocalVarNode ) {
        addNodeTag( ret, ((LocalVarNode) base).getMethod() );
      } else {
        addNodeTag( ret, null );
      }
  }
  return ret;
    }
    /** Finds the AllocDotField for base AllocNode an and field
     * field, or returns null. */
    public AllocDotField findAllocDotField( AllocNode an, SparkField field ) {
  return an.dot( field );
    }
    /** Finds or creates the AllocDotField for base variable baseValue and field
     * field, of type t. */
    public AllocDotField makeAllocDotField( AllocNode an, SparkField field ) {
  AllocDotField ret = an.dot( field );
  if( ret == null ) {
      ret = new AllocDotField( this, an, field );
  }
  return ret;
    }

    public boolean addSimpleEdge( VarNode from, VarNode to ) {
  boolean ret = false;
        if( doAddSimpleEdge( from, to ) ) {
            edgeQueue.add( from );
            edgeQueue.add( to );
            ret = true;
        }
        if( opts.simple_edges_bidirectional() ) {
            if( doAddSimpleEdge( to, from ) ) {
                edgeQueue.add( to );
                edgeQueue.add( from );
                ret = true;
            }
        }
        return ret;
    }

    public boolean addStoreEdge( VarNode from, FieldRefNode to ) {
        if( !opts.rta() ) {
            if( doAddStoreEdge( from, to ) ) {
                edgeQueue.add( from );
                edgeQueue.add( to );
                return true;
            }
        }
        return false;
    }

    public boolean addLoadEdge( FieldRefNode from, VarNode to ) {
        if( !opts.rta() ) {
            if( doAddLoadEdge( from, to ) ) {
                edgeQueue.add( from );
                edgeQueue.add( to );
                return true;
            }
        }
        return false;
    }

    public boolean addAllocEdge( AllocNode from, VarNode to ) {
        FastHierarchy fh = typeManager.getFastHierarchy();
        if( fh == null || to.getType() == null
        || fh.canStoreType( from.getType(), to.getType() ) ) {
            if( doAddAllocEdge( from, to ) ) {
                edgeQueue.add( from );
                edgeQueue.add( to );
                return true;
            }
        }
        return false;
    }

    /** Adds an edge to the graph, returning false if it was already there. */
    public final boolean addEdge( Node from, Node to ) {
        from = from.getReplacement();
        to = to.getReplacement();
  if( from instanceof VarNode ) {
      if( to instanceof VarNode ) {
                return addSimpleEdge( (VarNode) from, (VarNode) to );
      } else {
                return addStoreEdge( (VarNode) from, (FieldRefNode) to );
      }
  } else if( from instanceof FieldRefNode ) {
            return addLoadEdge( (FieldRefNode) from, (VarNode) to );

  } else {
            return addAllocEdge( (AllocNode) from, (VarNode) to );
  }
    }

    protected ChunkedQueue edgeQueue = new ChunkedQueue();
    public QueueReader edgeReader() { return edgeQueue.reader(); }

    public int getNumAllocNodes() {
        return allocNodeNumberer.size();
    }
    public TypeManager getTypeManager() {
        return typeManager;
    }

    public void setOnFlyCallGraph( OnFlyCallGraph ofcg ) { this.ofcg = ofcg; }
    public OnFlyCallGraph getOnFlyCallGraph() { return ofcg; }
    public OnFlyCallGraph ofcg() { return ofcg; }
    /** Adds the base of a dereference to the list of dereferenced
     * variables. */
    public void addDereference( VarNode base ) {
        dereferences.add( base );
    }

    /** Returns list of dereferences variables. */
    public List<VarNode> getDereferences() {
        return dereferences;
    }

    public Map<Node, Tag> getNodeTags() {
        return nodeToTag;
    }

    private final ArrayNumberer allocNodeNumberer = new ArrayNumberer();
    public ArrayNumberer getAllocNodeNumberer() { return allocNodeNumberer; }
    private final ArrayNumberer varNodeNumberer = new ArrayNumberer();
    public ArrayNumberer getVarNodeNumberer() { return varNodeNumberer; }
    private final ArrayNumberer fieldRefNodeNumberer = new ArrayNumberer();
    public ArrayNumberer getFieldRefNodeNumberer() { return fieldRefNodeNumberer; }
    private final ArrayNumberer allocDotFieldNodeNumberer = new ArrayNumberer();
    public ArrayNumberer getAllocDotFieldNodeNumberer() { return allocDotFieldNodeNumberer; }


    /** Returns SparkOptions for this graph. */
    public SparkOptions getOpts() { return opts; }

    final public void addCallTarget( Edge e ) {
        if( !e.passesParameters() ) return;
        MethodPAG srcmpag = MethodPAG.v( this, e.src() );
        MethodPAG tgtmpag = MethodPAG.v( this, e.tgt() );
        if( e.isExplicit() || e.kind() == Kind.THREAD ) {
            addCallTarget( srcmpag, tgtmpag, (Stmt) e.srcUnit(),
                           e.srcCtxt(), e.tgtCtxt() );
        } else {
            if( e.kind() == Kind.PRIVILEGED ) {
                // Flow from first parameter of doPrivileged() invocation
                // to this of target, and from return of target to the
                // return of doPrivileged()

                InvokeExpr ie = e.srcStmt().getInvokeExpr();

                Node parm = srcmpag.nodeFactory().getNode( ie.getArg(0) );
                parm = srcmpag.parameterize( parm, e.srcCtxt() );
                parm = parm.getReplacement();

                Node thiz = tgtmpag.nodeFactory().caseThis();
                thiz = tgtmpag.parameterize( thiz, e.tgtCtxt() );
                thiz = thiz.getReplacement();

                addEdge( parm, thiz );
                callAssigns.put(ie, new Pair(parm, thiz));
                callToMethod.put(ie, srcmpag.getMethod());

                if( e.srcUnit() instanceof AssignStmt ) {
                    AssignStmt as = (AssignStmt) e.srcUnit();

                    Node ret = tgtmpag.nodeFactory().caseRet();
                    ret = tgtmpag.parameterize( ret, e.tgtCtxt() );
                    ret = ret.getReplacement();

                    Node lhs = srcmpag.nodeFactory().getNode(as.getLeftOp());
                    lhs = srcmpag.parameterize( lhs, e.srcCtxt() );
                    lhs = lhs.getReplacement();

                    addEdge( ret, lhs );
                    callAssigns.put(ie, new Pair(ret, lhs));
                    callToMethod.put(ie, srcmpag.getMethod());
                }
            } else if( e.kind() == Kind.FINALIZE ) {
                Node srcThis = srcmpag.nodeFactory().caseThis();
                srcThis = srcmpag.parameterize( srcThis, e.srcCtxt() );
                srcThis = srcThis.getReplacement();

                Node tgtThis = tgtmpag.nodeFactory().caseThis();
                tgtThis = tgtmpag.parameterize( tgtThis, e.tgtCtxt() );
                tgtThis = tgtThis.getReplacement();

                addEdge( srcThis, tgtThis );
            } else if( e.kind() == Kind.NEWINSTANCE ) {
                Stmt s = (Stmt) e.srcUnit();
                InstanceInvokeExpr iie = (InstanceInvokeExpr) s.getInvokeExpr();

                Node cls = srcmpag.nodeFactory().getNode( iie.getBase() );
                cls = srcmpag.parameterize( cls, e.srcCtxt() );
                cls = cls.getReplacement();
                Node newObject = nodeFactory.caseNewInstance( (VarNode) cls );

                Node initThis = tgtmpag.nodeFactory().caseThis();
                initThis = tgtmpag.parameterize( initThis, e.tgtCtxt() );
                initThis = initThis.getReplacement();

                addEdge( newObject, initThis );
                if (s instanceof AssignStmt) {
                    AssignStmt as = (AssignStmt)s;
                    Node asLHS = srcmpag.nodeFactory().getNode(as.getLeftOp());
                    asLHS = srcmpag.parameterize( asLHS, e.srcCtxt());
                    asLHS = asLHS.getReplacement();
                    addEdge( newObject, asLHS);
                }
                callAssigns.put(s.getInvokeExpr(), new Pair(newObject, initThis));
                callToMethod.put(s.getInvokeExpr(), srcmpag.getMethod());
            } else if( e.kind() == Kind.REFL_INVOKE ) {
              // Flow (1) from first parameter of invoke(..) invocation
                // to this of target, (2) from the contents of the second (array) parameter
              // to all parameters of the target, and (3)  from return of target to the
                // return of invoke(..)
             
              //(1)
                InvokeExpr ie = e.srcStmt().getInvokeExpr();

                Value arg0 = ie.getArg(0);
                //if "null" is passed in, omit the edge
                if(arg0!=NullConstant.v()) {
          Node parm0 = srcmpag.nodeFactory().getNode( arg0 );
                  parm0 = srcmpag.parameterize( parm0, e.srcCtxt() );
                  parm0 = parm0.getReplacement();
 
                  Node thiz = tgtmpag.nodeFactory().caseThis();
                  thiz = tgtmpag.parameterize( thiz, e.tgtCtxt() );
                  thiz = thiz.getReplacement();
 
                  addEdge( parm0, thiz );
                  callAssigns.put(ie, new Pair(parm0, thiz));
                  callToMethod.put(ie, srcmpag.getMethod());
                }

              //(2)
                Value arg1 = ie.getArg(1);
                SootMethod tgt = e.getTgt().method();
                //if "null" is passed in, or target has no parameters, omit the edge
                if(arg1!=NullConstant.v() && tgt.getParameterCount()>0) {
          Node parm1 = srcmpag.nodeFactory().getNode( arg1 );
                  parm1 = srcmpag.parameterize( parm1, e.srcCtxt() );
                  parm1 = parm1.getReplacement();
                  FieldRefNode parm1contents = makeFieldRefNode( (VarNode) parm1, ArrayElement.v() );
                 
                  for(int i=0;i<tgt.getParameterCount(); i++) {
                    //if no reference type, create no edge
                    if(!(tgt.getParameterType(i) instanceof RefLikeType)) continue;
                   
                      Node tgtParmI = tgtmpag.nodeFactory().caseParm( i );
                      tgtParmI = tgtmpag.parameterize( tgtParmI, e.tgtCtxt() );
                      tgtParmI = tgtParmI.getReplacement();
 
                      addEdge( parm1contents, tgtParmI );
                      callAssigns.put(ie, new Pair(parm1contents, tgtParmI));
                  }
                }

                //(3)
                //only create return edge if we are actually assigning the return value and
                //the return type of the callee is actually a reference type
                if( e.srcUnit() instanceof AssignStmt && (tgt.getReturnType() instanceof RefLikeType)) {
                    AssignStmt as = (AssignStmt) e.srcUnit();

                    Node ret = tgtmpag.nodeFactory().caseRet();
                    ret = tgtmpag.parameterize( ret, e.tgtCtxt() );
                    ret = ret.getReplacement();

                    Node lhs = srcmpag.nodeFactory().getNode(as.getLeftOp());
                    lhs = srcmpag.parameterize( lhs, e.srcCtxt() );
                    lhs = lhs.getReplacement();

                    addEdge( ret, lhs );
                    callAssigns.put(ie, new Pair(ret, lhs));
                }
            } else if( e.kind() == Kind.REFL_CLASS_NEWINSTANCE || e.kind() == Kind.REFL_CONSTR_NEWINSTANCE) {
              // (1) create a fresh node for the new object
              // (2) create edge from this object to "this" of the constructor
              // (3) if this is a call to Constructor.newInstance and not Class.newInstance,
              //     create edges passing the contents of the arguments array of the call
              //     to all possible parameters of the target
              // (4) if we are inside an assign statement,
              //     assign the fresh object from (1) to the LHS of the assign statement
             
                Stmt s = (Stmt) e.srcUnit();
                InstanceInvokeExpr iie = (InstanceInvokeExpr) s.getInvokeExpr();

                //(1)
                Node cls = srcmpag.nodeFactory().getNode( iie.getBase() );
                cls = srcmpag.parameterize( cls, e.srcCtxt() );
                cls = cls.getReplacement();
                if( cls instanceof ContextVarNode ) cls = findLocalVarNode( ((VarNode)cls).getVariable() );
               
                VarNode newObject = makeGlobalVarNode( cls, RefType.v( "java.lang.Object" ) );
                SootClass tgtClass = e.getTgt().method().getDeclaringClass();
        RefType tgtType = tgtClass.getType();               
                AllocNode site = makeAllocNode( new Pair(cls, tgtClass), tgtType, null );
                addEdge( site, newObject );

                //(2)
                Node initThis = tgtmpag.nodeFactory().caseThis();
                initThis = tgtmpag.parameterize( initThis, e.tgtCtxt() );
                initThis = initThis.getReplacement();
                addEdge( newObject, initThis );
               
                //(3)
                if(e.kind() == Kind.REFL_CONSTR_NEWINSTANCE) {
                  Value arg = iie.getArg(0);
                  SootMethod tgt = e.getTgt().method();
                  //if "null" is passed in, or target has no parameters, omit the edge
                  if(arg!=NullConstant.v() && tgt.getParameterCount()>0) {
            Node parm0 = srcmpag.nodeFactory().getNode( arg );
                    parm0 = srcmpag.parameterize( parm0, e.srcCtxt() );
                    parm0 = parm0.getReplacement();
                    FieldRefNode parm1contents = makeFieldRefNode( (VarNode) parm0, ArrayElement.v() );
                   
                    for(int i=0;i<tgt.getParameterCount(); i++) {
                      //if no reference type, create no edge
                      if(!(tgt.getParameterType(i) instanceof RefLikeType)) continue;
                     
                        Node tgtParmI = tgtmpag.nodeFactory().caseParm( i );
                        tgtParmI = tgtmpag.parameterize( tgtParmI, e.tgtCtxt() );
                        tgtParmI = tgtParmI.getReplacement();
   
                        addEdge( parm1contents, tgtParmI );
                        callAssigns.put(iie, new Pair(parm1contents, tgtParmI));
                    }
                  }
                }
               
                //(4)
                if (s instanceof AssignStmt) {
                    AssignStmt as = (AssignStmt)s;
                    Node asLHS = srcmpag.nodeFactory().getNode(as.getLeftOp());
                    asLHS = srcmpag.parameterize( asLHS, e.srcCtxt());
                    asLHS = asLHS.getReplacement();
                    addEdge( newObject, asLHS);
                }
                callAssigns.put(s.getInvokeExpr(), new Pair(newObject, initThis));
                callToMethod.put(s.getInvokeExpr(), srcmpag.getMethod());
            } else {
                throw new RuntimeException( "Unhandled edge "+e );
            }
        }
    }

   
    /** Adds method target as a possible target of the invoke expression in s.
     * If target is null, only creates the nodes for the call site,
     * without actually connecting them to any target method.
     **/
    final public void addCallTarget( MethodPAG srcmpag,
                                     MethodPAG tgtmpag,
                                     Stmt s,
                                     Context srcContext,
                                     Context tgtContext ) {
        MethodNodeFactory srcnf = srcmpag.nodeFactory();
        MethodNodeFactory tgtnf = tgtmpag.nodeFactory();
        InvokeExpr ie = s.getInvokeExpr();
        boolean virtualCall = callAssigns.containsKey(ie);
        int numArgs = ie.getArgCount();
        for( int i = 0; i < numArgs; i++ ) {
            Value arg = ie.getArg( i );
            if( !( arg.getType() instanceof RefLikeType ) ) continue;
            if( arg instanceof NullConstant ) continue;

            Node argNode = srcnf.getNode( arg );
            argNode = srcmpag.parameterize( argNode, srcContext );
            argNode = argNode.getReplacement();

            Node parm = tgtnf.caseParm( i );
            parm = tgtmpag.parameterize( parm, tgtContext );
            parm = parm.getReplacement();

            addEdge( argNode, parm );
            callAssigns.put(ie, new Pair(argNode, parm));
            callToMethod.put(ie, srcmpag.getMethod());
           
        }
        if( ie instanceof InstanceInvokeExpr ) {
            InstanceInvokeExpr iie = (InstanceInvokeExpr) ie;

            Node baseNode = srcnf.getNode( iie.getBase() );
            baseNode = srcmpag.parameterize( baseNode, srcContext );
            baseNode = baseNode.getReplacement();

            Node thisRef = tgtnf.caseThis();
            thisRef = tgtmpag.parameterize( thisRef, tgtContext );
            thisRef = thisRef.getReplacement();
            addEdge( baseNode, thisRef );
            callAssigns.put(ie, new Pair(baseNode, thisRef));
            callToMethod.put(ie, srcmpag.getMethod());
            if (virtualCall && !virtualCallsToReceivers.containsKey(ie)) {
                virtualCallsToReceivers.put(ie, baseNode);
            }
        }
        if( s instanceof AssignStmt ) {
            Value dest = ( (AssignStmt) s ).getLeftOp();
            if( dest.getType() instanceof RefLikeType && !(dest instanceof NullConstant) ) {

                Node destNode = srcnf.getNode( dest );
                destNode = srcmpag.parameterize( destNode, srcContext );
                destNode = destNode.getReplacement();

                Node retNode = tgtnf.caseRet();
                retNode = tgtmpag.parameterize( retNode, tgtContext );
                retNode = retNode.getReplacement();

                addEdge( retNode, destNode );
                callAssigns.put(ie, new Pair(retNode, destNode));
                callToMethod.put(ie, srcmpag.getMethod());
            }
        }
    }
    /* End of package methods. */

    protected SparkOptions opts;

    protected Map<Object, Object> simple = new HashMap<Object, Object>();
    protected Map<Object, Object> load = new HashMap<Object, Object>();
    protected Map<Object, Object> store = new HashMap<Object, Object>();
    protected Map<Object, Object> alloc = new HashMap<Object, Object>();

    protected Map<Object, Object> simpleInv = new HashMap<Object, Object>();
    protected Map<Object, Object> loadInv = new HashMap<Object, Object>();
    protected Map<Object, Object> storeInv = new HashMap<Object, Object>();
    protected Map<Object, Object> allocInv = new HashMap<Object, Object>();

    protected boolean addToMap( Map<Object, Object> m, Node key, Node value ) {
  Object valueList = m.get( key );

  if( valueList == null ) {
      m.put( key, valueList = new HashSet(4) );
  } else if( !(valueList instanceof Set) ) {
      Node[] ar = (Node[]) valueList;
            HashSet<Node> vl = new HashSet<Node>(ar.length+4);
            m.put( key, vl );
            for (Node element : ar)
        vl.add( element );
            return vl.add( value );
            /*
      Node[] ar = (Node[]) valueList;
            Node[] newar = new Node[ar.length+1];
            for( int i = 0; i < ar.length; i++ ) {
                Node n = ar[i];
                if( n == value ) return false;
                newar[i] = n;
            }
            newar[ar.length] = value;
            m.put( key, newar );
            return true;
            */
  }
  return ((Set<Node>) valueList).add( value );
    }
    private final Map<Object, LocalVarNode> valToLocalVarNode = new HashMap<Object, LocalVarNode>(1000);
    private final Map<Object, GlobalVarNode> valToGlobalVarNode = new HashMap<Object, GlobalVarNode>(1000);
    private final Map<Object, AllocNode> valToAllocNode = new HashMap<Object, AllocNode>(1000);
    private OnFlyCallGraph ofcg;
    private final ArrayList<VarNode> dereferences = new ArrayList<VarNode>();
    protected TypeManager typeManager;
    private final LargeNumberedMap localToNodeMap = new LargeNumberedMap( Scene.v().getLocalNumberer() );
    public int maxFinishNumber = 0;
    private Map<Node, Tag> nodeToTag;
    private final GlobalNodeFactory nodeFactory = new GlobalNodeFactory(this);
    public GlobalNodeFactory nodeFactory() { return nodeFactory; }
    public NativeMethodDriver nativeMethodDriver;

    public HashMultiMap /* InvokeExpr -> Set[Pair] */ callAssigns = new HashMultiMap();
    public Map<InvokeExpr, SootMethod> callToMethod = new HashMap<InvokeExpr, SootMethod>();
    public Map<InvokeExpr, Node> virtualCallsToReceivers = new HashMap<InvokeExpr, Node>();
   
}
TOP

Related Classes of soot.jimple.spark.pag.PAG

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.