Exemple #1
0
  @Test
  public void testClassAnnotations2() throws Exception {
    TypeReference typeUnderTest =
        TypeReference.findOrCreate(
            ClassLoaderReference.Application, "Lannotations/AnnotatedClass2");

    Collection<Annotation> expectedRuntimeInvisibleAnnotations = HashSetFactory.make();
    expectedRuntimeInvisibleAnnotations.add(
        Annotation.make(
            TypeReference.findOrCreate(
                ClassLoaderReference.Application, "Lannotations/RuntimeInvisableAnnotation")));
    expectedRuntimeInvisibleAnnotations.add(
        Annotation.make(
            TypeReference.findOrCreate(
                ClassLoaderReference.Application, "Lannotations/RuntimeInvisableAnnotation2")));

    Collection<Annotation> expectedRuntimeVisibleAnnotations = HashSetFactory.make();
    expectedRuntimeVisibleAnnotations.add(
        Annotation.make(
            TypeReference.findOrCreate(
                ClassLoaderReference.Application, "Lannotations/RuntimeVisableAnnotation")));
    expectedRuntimeVisibleAnnotations.add(
        Annotation.make(
            TypeReference.findOrCreate(
                ClassLoaderReference.Application, "Lannotations/RuntimeVisableAnnotation2")));

    testClassAnnotations(
        typeUnderTest, expectedRuntimeInvisibleAnnotations, expectedRuntimeVisibleAnnotations);
  }
  /** @return Collection of IClasses, representing the interfaces this class implements. */
  protected Collection<IClass> computeAllInterfacesAsCollection() {
    Collection<? extends IClass> c = getDirectInterfaces();
    Set<IClass> result = HashSetFactory.make();
    for (Iterator<? extends IClass> it = c.iterator(); it.hasNext(); ) {
      IClass klass = it.next();
      if (klass.isInterface()) {
        result.add(klass);
      } else {
        Warnings.add(ClassHierarchyWarning.create("expected an interface " + klass));
      }
    }

    // at this point result holds all interfaces the class directly extends.
    // now expand to a fixed point.
    Set<IClass> last = null;
    do {
      last = HashSetFactory.make(result);
      for (IClass i : last) {
        result.addAll(i.getDirectInterfaces());
      }
    } while (last.size() < result.size());

    // now add any interfaces implemented by the super class
    IClass sup = null;
    sup = getSuperclass();
    if (sup != null) {
      result.addAll(sup.getAllImplementedInterfaces());
    }
    return result;
  }
Exemple #3
0
  private static class PredicateTableImpl implements PredicateTable {
    private final Set<String> hasSpills = HashSetFactory.make();
    private final Set<String> oneToOne = HashSetFactory.make();
    private final Map<String, Db2Type> types = HashMapFactory.make();
    private final Map<String, int[]> hashes = HashMapFactory.make();

    @Override
    public boolean hasSpills(String predicate) {
      return hasSpills.contains(predicate);
    }

    @Override
    public boolean hasSpills() {
      return !hasSpills.isEmpty();
    }

    @Override
    public boolean isOneToOne(String predicate) {
      return oneToOne.contains(predicate);
    }

    @Override
    public Db2Type getType(String predicate) {
      return types.get(predicate);
    }

    @Override
    public int getHashCount(String predicate) {
      if (hashes.containsKey(predicate)) {
        return hashes.get(predicate).length;
      } else {
        return 0;
      }
    }

    @Override
    public int[] getHashes(String predicate) {
      return hashes.get(predicate);
    }

    private void setPredicate(
        String predicate, boolean hasSpill, boolean oneToOne, String type, int[] hashes) {
      if (hasSpill) {
        this.hasSpills.add(predicate);
      }
      if (oneToOne) {
        this.oneToOne.add(predicate);
      }
      this.types.put(predicate, Db2Type.valueOf(type.toUpperCase()));
      this.hashes.put(predicate, hashes);
    }
  }
  private Set<CGNode> findRecursiveMethods(IProgressMonitor progress) throws CancelException {
    CallGraph cg = sdg.getCallGraph();
    GraphReachability<CGNode, CGNode> reach =
        new GraphReachability<CGNode, CGNode>(cg, new TrueFilter());
    progress.subTask("Searching recursive methods");
    reach.solve(progress);

    Set<CGNode> recursive = HashSetFactory.make();

    for (CGNode node : cg) {
      OrdinalSet<CGNode> rset = reach.getReachableSet(node);
      for (CGNode target : rset) {
        if (target != node) {
          OrdinalSet<CGNode> tset = reach.getReachableSet(target);
          if (tset.contains(node)) {
            recursive.add(node);
            break;
          }
        }
      }

      progress.worked(1);
    }

    progress.done();

    return recursive;
  }
  private Set<CGNode> findLoopingMethods(IProgressMonitor progress) throws CancelException {
    CallGraph cg = sdg.getCallGraph();
    Set<CGNode> loops = HashSetFactory.make();

    progress.subTask("Searching methods with potential endless loops");

    for (CGNode node : cg) {
      IR ir = node.getIR();
      if (ir != null) {
        ControlFlowGraph<SSAInstruction, ISSABasicBlock> cfg = ir.getControlFlowGraph();
        final boolean ac = Acyclic.isAcyclic(cfg, cfg.entry());
        if (!ac && !loopsAreSimple(ir)) {
          loops.add(node);
        }
      } else {
        // Conservatively assume that methods may not terminate, iff we dont
        // have their code
        loops.add(node);
      }

      progress.worked(1);
    }

    progress.done();

    return loops;
  }
 private Set<Variable> getProjectedVariables() {
   Set<Variable> ret = HashSetFactory.make();
   for (ProjectedVariable pv : gatherRealProjectedVariables()) {
     ret.add(pv.getVariable());
   }
   return ret;
 }
Exemple #7
0
  private void analyze() {
    Graph<T> DT = dom.dominatorTree();

    Iterator<T> XS = DFS.iterateFinishTime(DT, new NonNullSingletonIterator<T>(root));
    while (XS.hasNext()) {
      T X = XS.next();
      Set<T> DF_X = HashSetFactory.make();
      DF.put(X, DF_X);

      // DF_local
      for (Iterator<? extends T> YS = G.getSuccNodes(X); YS.hasNext(); ) {
        T Y = YS.next();
        if (dom.getIdom(Y) != X) {
          DF_X.add(Y);
        }
      }

      // DF_up
      for (Iterator<? extends T> ZS = DT.getSuccNodes(X); ZS.hasNext(); ) {
        T Z = ZS.next();
        for (Iterator<T> YS2 = getDominanceFrontier(Z); YS2.hasNext(); ) {
          T Y2 = YS2.next();
          if (dom.getIdom(Y2) != X) DF_X.add(Y2);
        }
      }
    }
  }
  private Set<CallNode> compute(IProgressMonitor progress) throws CancelException {
    Set<CallNode> calls = HashSetFactory.make();

    Set<CGNode> recursive = findRecursiveMethods(progress);

    Set<CGNode> loop = findLoopingMethods(progress);

    CallGraph cg = sdg.getCallGraph();
    Graph<CGNode> inverted = GraphInverter.invert(cg);
    GraphReachability<CGNode, CGNode> reach =
        new GraphReachability<CGNode, CGNode>(inverted, new TrueFilter());
    progress.subTask("Searching potential non-returning calls");
    reach.solve(progress);

    Set<CGNode> roots = HashSetFactory.make(loop);
    roots.addAll(recursive);

    OrdinalSet<CGNode> potential = OrdinalSet.empty();

    for (CGNode root : roots) {
      OrdinalSet<CGNode> reached = reach.getReachableSet(root);
      potential = OrdinalSet.unify(potential, reached);
    }

    Set<CGNode> terminating = HashSetFactory.make();
    Set<CGNode> nonTerminating = HashSetFactory.make();

    for (CGNode node : cg) {
      if (potential.contains(node)) {
        nonTerminating.add(node);
      } else {
        terminating.add(node);
      }
    }

    for (Call call : sdg.getAllCalls()) {
      if (nonTerminating.contains(call.callee.getCallGraphNode())) {
        calls.add(call.node);
      }
    }

    progress.done();

    computeControlDependence(calls, progress);

    return calls;
  }
 /**
  * Get all non-constructor, non-class-initializer methods declared by a class if their name is
  * equal to the specified name.
  *
  * @param cls the class
  * @param name the name
  */
 private Collection<IMethod> getDeclaredNormalMethods(IClass cls, Atom name) {
   Collection<IMethod> result = HashSetFactory.make();
   for (IMethod m : cls.getDeclaredMethods()) {
     if (!m.isInit() && !m.isClinit() && m.getSelector().getName().equals(name)) {
       result.add(m);
     }
   }
   return result;
 }
 @Override
 public Set<Pattern> gatherSubPatternsExcluding(Pattern except, boolean includeOptionals) {
   if (!except.equals(this)) {
     Set<Pattern> ret = HashSetFactory.make();
     ret.add(this);
     return ret;
   } else {
     return Collections.emptySet();
   }
 }
  private Set<CallNode> getCallsForInstruction(SSAInvokeInstruction invk) {
    Set<CallNode> calls = HashSetFactory.make();

    for (CallNode c : pdg.getAllCalls()) {
      if (c.getInstruction() == invk) {
        calls.add(c);
      }
    }

    return calls;
  }
  /**
   * Returns all concrete classes implementing the given interface or any subinterfaces
   *
   * @param iRoot
   * @return
   */
  public Collection<IClass> concreteClassesForInterface(IClass iRoot) {
    Set<IClass> clazzes = HashSetFactory.make();
    Set<IClass> done = HashSetFactory.make();
    Deque<IClass> todo = Queues.newArrayDeque();
    todo.push(iRoot);

    while (!todo.isEmpty()) {
      IClass i = todo.pop();
      for (IClass clazz : cha.getImplementors(i.getReference())) {
        if (clazz.isInterface() && !done.contains(clazz)) {
          done.add(i);
          todo.push(clazz);
        } else if (!clazz.isAbstract()) {
          clazzes.add(clazz);
        }
      }
    }

    return clazzes;
  }
 /**
  * Get all non-constructor, non-class-initializer methods declared by a class and all its
  * superclasses if their name is equal to the specified name.
  *
  * @param cls the class
  * @param name the name
  */
 private Collection<IMethod> getAllNormalPublicMethods(IClass cls, Atom name) {
   Collection<IMethod> result = HashSetFactory.make();
   Collection<IMethod> allMethods = null;
   allMethods = cls.getAllMethods();
   for (IMethod m : allMethods) {
     if (!m.isInit() && !m.isClinit() && m.isPublic() && m.getSelector().getName().equals(name)) {
       result.add(m);
     }
   }
   return result;
 }
Exemple #14
0
  /*
   * @see com.ibm.wala.classLoader.IClass#getAllImplementedInterfaces()
   */
  @Override
  public Collection<IClass> getAllImplementedInterfaces() {
    HashSet<IClass> result = HashSetFactory.make(2);
    for (TypeReference ref : getClassLoader().getLanguage().getArrayInterfaces()) {
      IClass klass = loader.lookupClass(ref.getName());
      if (klass != null) {
        result.add(klass);
      }
    }

    return result;
  }
  private void removeArtificialNodes(Graph<AbstractPDGNode> cdg) {
    Set<AbstractPDGNode> toRemove = HashSetFactory.make();

    for (AbstractPDGNode node : cdg) {
      if (SDGControlFlowGraph.isArtificial(node)) {
        toRemove.add(node);
      }
    }

    for (AbstractPDGNode node : toRemove) {
      removeNode(cdg, node);
    }
  }
  /**
   * This does not filter non-heap nodes anymore, because they should also be included in the
   * controlflow Therefore we have to ignore them later on during the dataflow analysis.
   *
   * @param params
   * @return
   */
  private static final Set<AbstractParameterNode> filterExitNode(IParamSet<?> params) {
    Set<AbstractParameterNode> result = HashSetFactory.make();

    if (params == null) {
      return result;
    }

    for (AbstractParameterNode node : params) {
      if (!node.isExit()) {
        result.add(node);
      }
    }

    return result;
  }
  public void setGraphRestriction(BinaryUnion<Variable, IRI> graphRestriction) {
    // if (this.graphRestriction == null)
    {
      if (graphRestriction != null
          && graphRestriction.isFirstType()
          && gatherVariables().contains(graphRestriction.getFirst())
          && !getProjectedVariables().contains(graphRestriction.getFirst())) {
        // graph restriction variable already used in the local graph pattern
        // and is not visible outside
        // we need to
        // 1) use a new variable v (not used in this pattern or its ancestors)  for the graph
        // restriction
        // 2) project v
        // 3) set the graph restriction to v
        // 4) add in this subselect pattern a filter ?v = ?graphRestriction
        Set<Variable> vars = HashSetFactory.make();
        Pattern top = getTopAncestor();
        if (top != null) {
          vars.addAll(Planner.gatherInScopeVariables(top));
          if (top.getOptionalPatterns() != null) {
            for (Pattern op : top.getOptionalPatterns()) {
              vars.addAll(Planner.gatherInScopeVariables(op));
            }
          }
        }
        vars.addAll(gatherVariables());
        String prefix = "graphRestrictionGeneratedVar_";
        int id = OCUtils.nextAvailableSuffixVariable(OCUtils.getVariables(vars), prefix);
        Variable v = new Variable(prefix + id);
        this.graphRestriction = new BinaryUnion<Variable, IRI>();
        this.graphRestriction.setFirst(v);

        if (selectClause.getProjectedVariables() == null
            || selectClause.getProjectedVariables().isEmpty()) {
          for (ProjectedVariable pv : gatherRealProjectedVariables()) {
            selectClause.addProjectedVariable(pv);
          }
        }
        selectClause.addProjectedVariable(new ProjectedVariable(v.getName()));
        // getParent().addFilter(new RelationalExpression(new
        // VariableExpression(graphRestriction.getFirst().getName()),
        //		 new VariableExpression(v.getName()), ERelationalOp.EQUAL));

      } else {
        this.graphRestriction = graphRestriction;
      }
    }
  }
Exemple #18
0
 /**
  * @param cha governing class hierarchy
  * @return the Set of CMR fields for this bean, including inherited CMRs
  */
 public static Set<Object> getCMRFields(
     BeanMetaData bean, DeploymentMetaData dmd, ClassHierarchy cha) {
   Set<Object> result = HashSetFactory.make(5);
   TypeReference T = bean.getEJBClass();
   while (T != null) {
     BeanMetaData B = dmd.getBeanMetaData(T);
     if (B != null) {
       result.addAll(B.getCMRFields());
     }
     IClass klass = cha.lookupClass(T);
     assert klass != null;
     IClass superKlass = klass.getSuperclass();
     T = (superKlass == null) ? null : superKlass.getReference();
   }
   return result;
 }
 @Override
 public Set<Variable> gatherIRIBoundVariables() {
   // TODO: Fix it everywhere where SimplePattern.gatherIRIBoundVariables is overriden.
   if (explicitIRIBoundVariables == null && explicitNotIRIBoundVariables == null) {
     return super.gatherIRIBoundVariables();
   } else {
     Set<Variable> ret = HashSetFactory.make(super.gatherIRIBoundVariables());
     if (explicitNotIRIBoundVariables != null) {
       ret.removeAll(explicitNotIRIBoundVariables);
     }
     if (explicitIRIBoundVariables != null) {
       ret.addAll(explicitIRIBoundVariables);
     }
     return ret;
   }
 }
 /**
  * side effect: populates the smush map.
  *
  * @return true iff the node contains too many allocation sites of type c
  */
 private boolean exceedsSmushLimit(IClass c, CGNode node) {
   Set<IClass> s = smushMap.get(node);
   if (s == null) {
     Map<IClass, Integer> count = countAllocsByType(node);
     HashSet<IClass> smushees = HashSetFactory.make(5);
     for (Iterator<Map.Entry<IClass, Integer>> it = count.entrySet().iterator(); it.hasNext(); ) {
       Map.Entry<IClass, Integer> e = it.next();
       Integer i = e.getValue();
       if (i.intValue() > SMUSH_LIMIT) {
         smushees.add(e.getKey());
       }
     }
     s = smushees.isEmpty() ? Collections.<IClass>emptySet() : smushees;
     smushMap.put(node, s);
   }
   return s.contains(c);
 }
Exemple #21
0
    protected Set<CGNode> getPossibleTargets(CallSiteReference site) {
      Object result = targets.get(site.getProgramCounter());

      if (result == null) {
        return Collections.emptySet();
      } else if (result instanceof CGNode) {
        Set<CGNode> s = Collections.singleton((CGNode) result);
        return s;
      } else {
        IntSet s = (IntSet) result;
        HashSet<CGNode> h = HashSetFactory.make(s.size());
        for (IntIterator it = s.intIterator(); it.hasNext(); ) {
          h.add(getCallGraph().getNode(it.next()));
        }
        return h;
      }
    }
    /* (non-Javadoc)
     * @see com.ibm.wala.fixedpoint.impl.AbstractFixedPointSolver#initializeVariables()
     */
    @Override
    protected void initializeVariables() {
      for (ISSABasicBlock bb : scc) {
        for (SSAInstruction ssa : bb) {
          BitVectorVariable bv = new BitVectorVariable();
          for (int i = 0; i < ssa.getNumberOfDefs(); i++) {
            final int def = ssa.getDef(i);
            bv.set(def);
          }

          transitive.put(ssa, bv);

          for (int i = 0; i < ssa.getNumberOfUses(); i++) {
            Integer use = ssa.getUse(i);
            Set<SSAInstruction> set = reads.get(use);
            if (set == null) {
              set = HashSetFactory.make();
              reads.put(use, set);
            }
            set.add(ssa);
          }
        }
      }

      final BitVectorOr or = new BitVectorOr(new BitVector());

      for (Entry<SSAInstruction, BitVectorVariable> entry : transitive.entrySet()) {
        SSAInstruction instr = entry.getKey();
        BitVectorVariable var = entry.getValue();

        for (int i = 0; i < instr.getNumberOfDefs(); i++) {
          final int def = instr.getDef(i);
          Set<SSAInstruction> users = reads.get(def);
          if (users != null) {
            for (SSAInstruction user : users) {
              // instr influences also all variables that are written by statements that use the
              // output of instr
              BitVectorVariable varUser = transitive.get(user);
              newStatement(var, or, varUser, true, false);
            }
          }
        }
      }
    }
 /**
  * collect the putstatic instructions in the call graph as {@link PathEdge} seeds for the
  * analysis
  */
 private Collection<PathEdge<BasicBlockInContext<IExplodedBasicBlock>>> collectInitialSeeds() {
   Collection<PathEdge<BasicBlockInContext<IExplodedBasicBlock>>> result = HashSetFactory.make();
   for (BasicBlockInContext<IExplodedBasicBlock> bb : supergraph) {
     IExplodedBasicBlock ebb = bb.getDelegate();
     SSAInstruction instruction = ebb.getInstruction();
     if (instruction instanceof SSAPutInstruction) {
       SSAPutInstruction putInstr = (SSAPutInstruction) instruction;
       if (putInstr.isStatic()) {
         final CGNode cgNode = bb.getNode();
         Pair<CGNode, Integer> fact = Pair.make(cgNode, ebb.getFirstInstructionIndex());
         int factNum = domain.add(fact);
         BasicBlockInContext<IExplodedBasicBlock> fakeEntry = getFakeEntry(cgNode);
         // note that the fact number used for the source of this path edge doesn't really matter
         result.add(PathEdge.createPathEdge(fakeEntry, factNum, bb, factNum));
       }
     }
   }
   return result;
 }
Exemple #24
0
 /** make main entrypoints, even in the primordial loader. */
 public static Iterable<Entrypoint> makePrimordialMainEntrypoints(
     AnalysisScope scope, ClassHierarchy cha) {
   final Atom mainMethod = Atom.findOrCreateAsciiAtom("main");
   final HashSet<Entrypoint> result = HashSetFactory.make();
   for (IClass klass : cha) {
     MethodReference mainRef =
         MethodReference.findOrCreate(
             klass.getReference(),
             mainMethod,
             Descriptor.findOrCreateUTF8("([Ljava/lang/String;)V"));
     IMethod m = klass.getMethod(mainRef.getSelector());
     if (m != null) {
       result.add(new DefaultEntrypoint(m, cha));
     }
   }
   return new Iterable<Entrypoint>() {
     @Override
     public Iterator<Entrypoint> iterator() {
       return result.iterator();
     }
   };
 }
Exemple #25
0
  public static Iterable<Entrypoint> makePrimordialPublicEntrypoints(
      AnalysisScope scope, ClassHierarchy cha, String pkg) {
    final HashSet<Entrypoint> result = HashSetFactory.make();
    for (IClass clazz : cha) {

      if (clazz.getName().toString().indexOf(pkg) != -1
          && !clazz.isInterface()
          && !clazz.isAbstract()) {
        for (IMethod method : clazz.getDeclaredMethods()) {
          if (method.isPublic() && !method.isAbstract()) {
            System.out.println("Entry:" + method.getReference());
            result.add(new DefaultEntrypoint(method, cha));
          }
        }
      }
    }
    return new Iterable<Entrypoint>() {
      @Override
      public Iterator<Entrypoint> iterator() {
        return result.iterator();
      }
    };
  }
  public static ExceptionPruneAnalysis create(String methodSig)
      throws WalaException, IOException, IllegalArgumentException, CallGraphBuilderCancelException {
    AnalysisScope scope = AnalysisScopeReader.makePrimordialScope(null);

    SetOfClasses exclusions =
        new FileOfClasses(new ByteArrayInputStream(exclusionRegExp.getBytes()));
    scope.setExclusions(exclusions);

    ClassLoaderReference loader = scope.getLoader(AnalysisScope.APPLICATION);
    AnalysisScopeReader.addClassPathToScope(classPath, scope, loader);

    // Klassenhierarchie berechnen
    ClassHierarchy cha = ClassHierarchy.make(scope);

    AnalysisCache cache = new AnalysisCache();

    MethodReference mr = StringStuff.makeMethodReference(Language.JAVA, methodSig);
    IMethod m = cha.resolveMethod(mr);
    if (m == null) {
      throw new IllegalStateException("Could not resolve " + mr);
    }

    Set<Entrypoint> entries = HashSetFactory.make();
    entries.add(new DefaultEntrypoint(m, cha));
    AnalysisOptions options = new AnalysisOptions();
    options.getSSAOptions().setPiNodePolicy(SSAOptions.getAllBuiltInPiNodes());
    options.setEntrypoints(entries);
    CallGraphBuilder builder = Util.makeZeroOneContainerCFABuilder(options, cache, cha, scope);
    CallGraph cg = builder.makeCallGraph(options, null);

    PointerAnalysis pta = builder.getPointerAnalysis();

    ExceptionPruneAnalysis mCFG = new ExceptionPruneAnalysis(cg, pta, cache);

    return mCFG;
  }
Exemple #27
0
/** A graph of basic blocks. */
public class ShrikeCFG extends AbstractCFG<IInstruction, ShrikeCFG.BasicBlock> {

  private static final boolean DEBUG = false;

  private int[] instruction2Block;

  private final IBytecodeMethod method;

  /** Cache this here for efficiency */
  private final int hashBase;

  /** Set of Shrike {@link ExceptionHandler} objects that cover this method. */
  private final Set<ExceptionHandler> exceptionHandlers = HashSetFactory.make(10);

  public ShrikeCFG(IBytecodeMethod method) throws IllegalArgumentException {
    super(method);
    if (method == null) {
      throw new IllegalArgumentException("method cannot be null");
    }
    this.method = method;
    this.hashBase = method.hashCode() * 9967;
    makeBasicBlocks();
    init();
    computeI2BMapping();
    computeEdges();

    if (DEBUG) {
      System.err.println(this);
    }
  }

  @Override
  public IBytecodeMethod getMethod() {
    return method;
  }

  @Override
  public int hashCode() {
    return 9511 * getMethod().hashCode();
  }

  @Override
  public boolean equals(Object o) {
    return (o instanceof ShrikeCFG) && getMethod().equals(((ShrikeCFG) o).getMethod());
  }

  public IInstruction[] getInstructions() {
    try {
      return method.getInstructions();
    } catch (InvalidClassFileException e) {
      e.printStackTrace();
      Assertions.UNREACHABLE();
      return null;
    }
  }

  /**
   * Compute a mapping from instruction to basic block. Also, compute the blocks that end with a
   * 'normal' return.
   */
  private void computeI2BMapping() {
    instruction2Block = new int[getInstructions().length];
    for (Iterator it = iterator(); it.hasNext(); ) {
      final BasicBlock b = (BasicBlock) it.next();
      for (int j = b.getFirstInstructionIndex(); j <= b.getLastInstructionIndex(); j++) {
        instruction2Block[j] = getNumber(b);
      }
    }
  }

  /** Compute outgoing edges in the control flow graph. */
  private void computeEdges() {
    for (Iterator it = iterator(); it.hasNext(); ) {
      BasicBlock b = (BasicBlock) it.next();
      if (b.equals(exit())) {
        continue;
      } else if (b.equals(entry())) {
        BasicBlock bb0 = getBlockForInstruction(0);
        assert bb0 != null;
        addNormalEdge(b, bb0);
      } else {
        b.computeOutgoingEdges();
      }
    }
  }

  private void makeBasicBlocks() {
    ExceptionHandler[][] handlers;
    try {
      handlers = method.getHandlers();
    } catch (InvalidClassFileException e) {
      e.printStackTrace();
      Assertions.UNREACHABLE();
      handlers = null;
    }
    boolean[] r = new boolean[getInstructions().length];
    boolean[] catchers = new boolean[getInstructions().length];
    // we initially start with both the entry and exit block.
    int blockCount = 2;

    // Compute r so r[i] == true iff instruction i begins a basic block.
    // While doing so count the number of blocks.
    r[0] = true;
    IInstruction[] instructions = getInstructions();
    for (int i = 0; i < instructions.length; i++) {
      int[] targets = instructions[i].getBranchTargets();

      // if there are any targets, then break the basic block here.
      // also break the basic block after a return
      if (targets.length > 0 || !instructions[i].isFallThrough()) {
        if (i + 1 < instructions.length && !r[i + 1]) {
          r[i + 1] = true;
          blockCount++;
        }
      }

      for (int j = 0; j < targets.length; j++) {
        if (!r[targets[j]]) {
          r[targets[j]] = true;
          blockCount++;
        }
      }
      if (instructions[i].isPEI()) {
        ExceptionHandler[] hs = handlers[i];
        // break the basic block here.
        if (i + 1 < instructions.length && !r[i + 1]) {
          r[i + 1] = true;
          blockCount++;
        }
        if (hs != null && hs.length > 0) {
          for (int j = 0; j < hs.length; j++) {
            exceptionHandlers.add(hs[j]);
            if (!r[hs[j].getHandler()]) {
              // we have not discovered the catch block yet.
              // form a new basic block
              r[hs[j].getHandler()] = true;
              blockCount++;
            }
            catchers[hs[j].getHandler()] = true;
          }
        }
      }
    }

    BasicBlock entry = new BasicBlock(-1);
    addNode(entry);

    int j = 1;
    for (int i = 0; i < r.length; i++) {
      if (r[i]) {
        BasicBlock b = new BasicBlock(i);
        addNode(b);
        if (catchers[i]) {
          setCatchBlock(j);
        }
        j++;
      }
    }

    BasicBlock exit = new BasicBlock(-1);
    addNode(exit);
  }

  /**
   * Return an instruction's basic block in the CFG given the index of the instruction in the CFG's
   * instruction array.
   */
  public BasicBlock getBlockForInstruction(int index) {
    return getNode(instruction2Block[index]);
  }

  public final class BasicBlock extends NodeWithNumber implements IBasicBlock<IInstruction> {

    /** The number of the ShrikeBT instruction that begins this block. */
    private final int startIndex;

    public BasicBlock(int startIndex) {
      this.startIndex = startIndex;
    }

    public boolean isCatchBlock() {
      return ShrikeCFG.this.isCatchBlock(getNumber());
    }

    private void computeOutgoingEdges() {
      if (DEBUG) {
        System.err.println("Block " + this + ": computeOutgoingEdges()");
      }

      IInstruction last = getInstructions()[getLastInstructionIndex()];
      int[] targets = last.getBranchTargets();
      for (int i = 0; i < targets.length; i++) {
        BasicBlock b = getBlockForInstruction(targets[i]);
        addNormalEdgeTo(b);
      }
      addExceptionalEdges(last);
      if (last.isFallThrough()) {
        BasicBlock next = getNode(getNumber() + 1);
        addNormalEdgeTo(next);
      }
      if (last instanceof ReturnInstruction) {
        // link each return instruction to the exit block.
        BasicBlock exit = exit();
        addNormalEdgeTo(exit);
      }
    }

    /**
     * Add any exceptional edges generated by the last instruction in a basic block.
     *
     * @param last the last instruction in a basic block.
     */
    protected void addExceptionalEdges(IInstruction last) {
      IClassHierarchy cha = getMethod().getClassHierarchy();
      if (last.isPEI()) {
        Collection<TypeReference> exceptionTypes = null;
        boolean goToAllHandlers = false;

        ExceptionHandler[] hs = getExceptionHandlers();
        if (last instanceof ThrowInstruction) {
          // this class does not have the type information needed
          // to determine what the athrow throws. So, add an
          // edge to all reachable handlers. Better information can
          // be obtained later with SSA type propagation.
          // TODO: consider pruning to only the exception types that
          // this method either catches or allocates, since these are
          // the only types that can flow to an athrow.
          goToAllHandlers = true;
        } else {
          if (hs != null && hs.length > 0) {
            IClassLoader loader = getMethod().getDeclaringClass().getClassLoader();
            BytecodeLanguage l = (BytecodeLanguage) loader.getLanguage();
            exceptionTypes = l.getImplicitExceptionTypes(last);
            if (last instanceof IInvokeInstruction) {
              IInvokeInstruction call = (IInvokeInstruction) last;
              exceptionTypes = HashSetFactory.make(exceptionTypes);
              MethodReference target =
                  MethodReference.findOrCreate(
                      l,
                      loader.getReference(),
                      call.getClassType(),
                      call.getMethodName(),
                      call.getMethodSignature());
              try {
                exceptionTypes.addAll(l.inferInvokeExceptions(target, cha));
              } catch (InvalidClassFileException e) {
                e.printStackTrace();
                Assertions.UNREACHABLE();
              }
            }
          }
        }

        if (hs != null && hs.length > 0) {
          // found a handler for this PEI

          // create a mutable copy
          if (!goToAllHandlers) {
            exceptionTypes = HashSetFactory.make(exceptionTypes);
          }

          // this var gets set to false if goToAllHandlers is true but some enclosing exception
          // handler catches all
          // exceptions.  in such a case, we need not add an exceptional edge to the method exit
          boolean needEdgeToExitForAllHandlers = true;
          for (int j = 0; j < hs.length; j++) {
            if (DEBUG) {
              System.err.println(" handler " + hs[j]);
            }
            BasicBlock b = getBlockForInstruction(hs[j].getHandler());
            if (DEBUG) {
              System.err.println(" target " + b);
            }
            if (goToAllHandlers) {
              // add an edge to the catch block.
              if (DEBUG) {
                System.err.println(" gotoAllHandlers " + b);
              }
              addExceptionalEdgeTo(b);
              // if the handler catches all exceptions, we don't need to add an edge to the exit or
              // any other handlers
              if (hs[j].getCatchClass() == null) {
                needEdgeToExitForAllHandlers = false;
                break;
              }
            } else {
              TypeReference caughtException = null;
              if (hs[j].getCatchClass() != null) {
                ClassLoaderReference loader =
                    ShrikeCFG.this.getMethod().getDeclaringClass().getReference().getClassLoader();
                caughtException = ShrikeUtil.makeTypeReference(loader, hs[j].getCatchClass());
                if (DEBUG) {
                  System.err.println(" caughtException " + caughtException);
                }
                IClass caughtClass = cha.lookupClass(caughtException);
                if (caughtClass == null) {
                  // conservatively add the edge, and raise a warning
                  addExceptionalEdgeTo(b);
                  Warnings.add(FailedExceptionResolutionWarning.create(caughtException));
                  // null out caughtException, to avoid attempting to process it
                  caughtException = null;
                }
              } else {
                if (DEBUG) {
                  System.err.println(" catchClass() == null");
                }
                // hs[j].getCatchClass() == null.
                // this means that the handler catches all exceptions.
                // add the edge and null out all types
                if (!exceptionTypes.isEmpty()) {
                  addExceptionalEdgeTo(b);
                  exceptionTypes.clear();
                  caughtException = null;
                }
              }
              if (caughtException != null) {
                IClass caughtClass = cha.lookupClass(caughtException);
                // the set "caught" should be the set of exceptions that MUST
                // have been caught by the handlers in scope
                ArrayList<TypeReference> caught =
                    new ArrayList<TypeReference>(exceptionTypes.size());
                // check if we should add an edge to the catch block.
                for (TypeReference t : exceptionTypes) {
                  if (t != null) {
                    IClass klass = cha.lookupClass(t);
                    if (klass == null) {
                      Warnings.add(FailedExceptionResolutionWarning.create(caughtException));
                      // conservatively add an edge
                      addExceptionalEdgeTo(b);
                    } else {
                      boolean subtype1 = cha.isSubclassOf(klass, caughtClass);
                      if (subtype1 || cha.isSubclassOf(caughtClass, klass)) {
                        // add the edge and null out the type from the array
                        addExceptionalEdgeTo(b);
                        if (subtype1) {
                          caught.add(t);
                        }
                      }
                    }
                  }
                }
                exceptionTypes.removeAll(caught);
              }
            }
          }
          // if needed, add an edge to the exit block.
          if ((exceptionTypes == null && needEdgeToExitForAllHandlers)
              || (exceptionTypes != null && !exceptionTypes.isEmpty())) {
            BasicBlock exit = exit();
            addExceptionalEdgeTo(exit);
          }
        } else {
          // found no handler for this PEI ... link to the exit block.
          BasicBlock exit = exit();
          addExceptionalEdgeTo(exit);
        }
      }
    }

    private ExceptionHandler[] getExceptionHandlers() {
      ExceptionHandler[][] handlers;
      try {
        handlers = method.getHandlers();
      } catch (InvalidClassFileException e) {
        e.printStackTrace();
        Assertions.UNREACHABLE();
        handlers = null;
      }
      ExceptionHandler[] hs = handlers[getLastInstructionIndex()];
      return hs;
    }

    private void addNormalEdgeTo(BasicBlock b) {
      addNormalEdge(this, b);
    }

    private void addExceptionalEdgeTo(BasicBlock b) {
      addExceptionalEdge(this, b);
    }

    public int getLastInstructionIndex() {
      if (this == entry() || this == exit()) {
        // these are the special end blocks
        return -2;
      }
      if (getNumber() == (getMaxNumber() - 1)) {
        // this is the last non-exit block
        return getInstructions().length - 1;
      } else {
        BasicBlock next = getNode(getNumber() + 1);
        return next.getFirstInstructionIndex() - 1;
      }
    }

    public int getFirstInstructionIndex() {
      return startIndex;
    }

    @Override
    public String toString() {
      return "BB[Shrike]"
          + getNumber()
          + " - "
          + method.getDeclaringClass().getReference().getName()
          + "."
          + method.getName();
    }

    /*
     * @see com.ibm.wala.cfg.BasicBlock#isExitBlock()
     */
    public boolean isExitBlock() {
      return this == ShrikeCFG.this.exit();
    }

    /*
     * @see com.ibm.wala.cfg.BasicBlock#isEntryBlock()
     */
    public boolean isEntryBlock() {
      return this == ShrikeCFG.this.entry();
    }

    /*
     * @see com.ibm.wala.cfg.BasicBlock#getMethod()
     */
    public IMethod getMethod() {
      return ShrikeCFG.this.getMethod();
    }

    @Override
    public int hashCode() {
      return hashBase + getNumber();
    }

    @Override
    public boolean equals(Object o) {
      return (o instanceof BasicBlock)
          && ((BasicBlock) o).getMethod().equals(getMethod())
          && ((BasicBlock) o).getNumber() == getNumber();
    }

    /*
     * @see com.ibm.wala.cfg.BasicBlock#getNumber()
     */
    public int getNumber() {
      return getGraphNodeId();
    }

    public Iterator<IInstruction> iterator() {
      return new ArrayIterator<IInstruction>(
          getInstructions(), getFirstInstructionIndex(), getLastInstructionIndex());
    }
  }

  @Override
  public String toString() {
    StringBuffer s = new StringBuffer("");
    for (Iterator it = iterator(); it.hasNext(); ) {
      BasicBlock bb = (BasicBlock) it.next();
      s.append("BB").append(getNumber(bb)).append("\n");
      for (int j = bb.getFirstInstructionIndex(); j <= bb.getLastInstructionIndex(); j++) {
        s.append("  ").append(j).append("  ").append(getInstructions()[j]).append("\n");
      }

      Iterator<BasicBlock> succNodes = getSuccNodes(bb);
      while (succNodes.hasNext()) {
        s.append("    -> BB").append(getNumber(succNodes.next())).append("\n");
      }
    }
    return s.toString();
  }

  public int getMaxStackHeight() {
    return method.getMaxStackHeight();
  }

  public int getMaxLocals() {
    return method.getMaxLocals();
  }

  public Set<ExceptionHandler> getExceptionHandlers() {
    return exceptionHandlers;
  }

  /*
   * @see com.ibm.wala.cfg.ControlFlowGraph#getProgramCounter(int)
   */
  public int getProgramCounter(int index) {
    try {
      return method.getBytecodeIndex(index);
    } catch (InvalidClassFileException e) {
      e.printStackTrace();
      Assertions.UNREACHABLE();
      return -1;
    }
  }

  /** A warning when we fail to resolve the type of an exception */
  private static class FailedExceptionResolutionWarning extends Warning {

    final TypeReference T;

    FailedExceptionResolutionWarning(TypeReference T) {
      super(Warning.MODERATE);
      this.T = T;
    }

    @Override
    public String getMsg() {
      return getClass().toString() + " : " + T;
    }

    public static FailedExceptionResolutionWarning create(TypeReference T) {
      return new FailedExceptionResolutionWarning(T);
    }
  }
}
Exemple #28
0
    /**
     * Add any exceptional edges generated by the last instruction in a basic block.
     *
     * @param last the last instruction in a basic block.
     */
    protected void addExceptionalEdges(IInstruction last) {
      IClassHierarchy cha = getMethod().getClassHierarchy();
      if (last.isPEI()) {
        Collection<TypeReference> exceptionTypes = null;
        boolean goToAllHandlers = false;

        ExceptionHandler[] hs = getExceptionHandlers();
        if (last instanceof ThrowInstruction) {
          // this class does not have the type information needed
          // to determine what the athrow throws. So, add an
          // edge to all reachable handlers. Better information can
          // be obtained later with SSA type propagation.
          // TODO: consider pruning to only the exception types that
          // this method either catches or allocates, since these are
          // the only types that can flow to an athrow.
          goToAllHandlers = true;
        } else {
          if (hs != null && hs.length > 0) {
            IClassLoader loader = getMethod().getDeclaringClass().getClassLoader();
            BytecodeLanguage l = (BytecodeLanguage) loader.getLanguage();
            exceptionTypes = l.getImplicitExceptionTypes(last);
            if (last instanceof IInvokeInstruction) {
              IInvokeInstruction call = (IInvokeInstruction) last;
              exceptionTypes = HashSetFactory.make(exceptionTypes);
              MethodReference target =
                  MethodReference.findOrCreate(
                      l,
                      loader.getReference(),
                      call.getClassType(),
                      call.getMethodName(),
                      call.getMethodSignature());
              try {
                exceptionTypes.addAll(l.inferInvokeExceptions(target, cha));
              } catch (InvalidClassFileException e) {
                e.printStackTrace();
                Assertions.UNREACHABLE();
              }
            }
          }
        }

        if (hs != null && hs.length > 0) {
          // found a handler for this PEI

          // create a mutable copy
          if (!goToAllHandlers) {
            exceptionTypes = HashSetFactory.make(exceptionTypes);
          }

          // this var gets set to false if goToAllHandlers is true but some enclosing exception
          // handler catches all
          // exceptions.  in such a case, we need not add an exceptional edge to the method exit
          boolean needEdgeToExitForAllHandlers = true;
          for (int j = 0; j < hs.length; j++) {
            if (DEBUG) {
              System.err.println(" handler " + hs[j]);
            }
            BasicBlock b = getBlockForInstruction(hs[j].getHandler());
            if (DEBUG) {
              System.err.println(" target " + b);
            }
            if (goToAllHandlers) {
              // add an edge to the catch block.
              if (DEBUG) {
                System.err.println(" gotoAllHandlers " + b);
              }
              addExceptionalEdgeTo(b);
              // if the handler catches all exceptions, we don't need to add an edge to the exit or
              // any other handlers
              if (hs[j].getCatchClass() == null) {
                needEdgeToExitForAllHandlers = false;
                break;
              }
            } else {
              TypeReference caughtException = null;
              if (hs[j].getCatchClass() != null) {
                ClassLoaderReference loader =
                    ShrikeCFG.this.getMethod().getDeclaringClass().getReference().getClassLoader();
                caughtException = ShrikeUtil.makeTypeReference(loader, hs[j].getCatchClass());
                if (DEBUG) {
                  System.err.println(" caughtException " + caughtException);
                }
                IClass caughtClass = cha.lookupClass(caughtException);
                if (caughtClass == null) {
                  // conservatively add the edge, and raise a warning
                  addExceptionalEdgeTo(b);
                  Warnings.add(FailedExceptionResolutionWarning.create(caughtException));
                  // null out caughtException, to avoid attempting to process it
                  caughtException = null;
                }
              } else {
                if (DEBUG) {
                  System.err.println(" catchClass() == null");
                }
                // hs[j].getCatchClass() == null.
                // this means that the handler catches all exceptions.
                // add the edge and null out all types
                if (!exceptionTypes.isEmpty()) {
                  addExceptionalEdgeTo(b);
                  exceptionTypes.clear();
                  caughtException = null;
                }
              }
              if (caughtException != null) {
                IClass caughtClass = cha.lookupClass(caughtException);
                // the set "caught" should be the set of exceptions that MUST
                // have been caught by the handlers in scope
                ArrayList<TypeReference> caught =
                    new ArrayList<TypeReference>(exceptionTypes.size());
                // check if we should add an edge to the catch block.
                for (TypeReference t : exceptionTypes) {
                  if (t != null) {
                    IClass klass = cha.lookupClass(t);
                    if (klass == null) {
                      Warnings.add(FailedExceptionResolutionWarning.create(caughtException));
                      // conservatively add an edge
                      addExceptionalEdgeTo(b);
                    } else {
                      boolean subtype1 = cha.isSubclassOf(klass, caughtClass);
                      if (subtype1 || cha.isSubclassOf(caughtClass, klass)) {
                        // add the edge and null out the type from the array
                        addExceptionalEdgeTo(b);
                        if (subtype1) {
                          caught.add(t);
                        }
                      }
                    }
                  }
                }
                exceptionTypes.removeAll(caught);
              }
            }
          }
          // if needed, add an edge to the exit block.
          if ((exceptionTypes == null && needEdgeToExitForAllHandlers)
              || (exceptionTypes != null && !exceptionTypes.isEmpty())) {
            BasicBlock exit = exit();
            addExceptionalEdgeTo(exit);
          }
        } else {
          // found no handler for this PEI ... link to the exit block.
          BasicBlock exit = exit();
          addExceptionalEdgeTo(exit);
        }
      }
    }
  // public static void addBypassLogic(AnalysisOptions options, AnalysisScope
  // scope, ClassLoader cl, String xmlFile,
  // IClassHierarchy cha) throws IllegalArgumentException {
  public static void addBypassLogic(
      AnalysisOptions options,
      AnalysisScope scope,
      InputStream xmlIStream,
      IClassHierarchy cha,
      MethodSummary extraSummary)
      throws IllegalArgumentException {

    if (scope == null) {
      throw new IllegalArgumentException("scope is null");
    }
    if (options == null) {
      throw new IllegalArgumentException("options is null");
    }
    // if (cl == null) {
    // throw new IllegalArgumentException("cl is null");
    // }
    if (cha == null) {
      throw new IllegalArgumentException("cha cannot be null");
    }

    InputStream s = null;
    try {
      Set<TypeReference> summaryClasses = HashSetFactory.make();
      Map<MethodReference, MethodSummary> summaries = HashMapFactory.make();

      if (null != xmlIStream) {
        XMLMethodSummaryReader newSummaryXML = loadMethodSummaries(scope, xmlIStream);
        summaryClasses.addAll(newSummaryXML.getAllocatableClasses());
        for (MethodSummary summary : newSummaryXML.getSummaries().values()) {
          logger.trace(
              "SSA instructions for summary of {}:\n{}",
              summary.getMethod().getSignature().toString(),
              Arrays.toString(summary.getStatements()));
        }
        summaries.putAll(newSummaryXML.getSummaries());
      }
      logger.debug("loaded " + summaries.size() + " new summaries");
      // for (MethodReference mr : summaries.keySet()) {
      // logger.debug("summary loaded for: "+mr.getSignature());
      // }

      s =
          new FileProvider()
              .getInputStreamFromClassLoader(
                  pathToSpec + File.separator + methodSpec,
                  AndroidAnalysisContext.class.getClassLoader());

      XMLMethodSummaryReader nativeSummaries = loadMethodSummaries(scope, s);

      logger.debug("loaded " + nativeSummaries.getSummaries().size() + " native summaries");

      summaries.putAll(nativeSummaries.getSummaries());
      summaryClasses.addAll(nativeSummaries.getAllocatableClasses());
      if (extraSummary != null) {
        summaries.put((MethodReference) extraSummary.getMethod(), extraSummary);
      }

      MethodTargetSelector ms =
          new BypassMethodTargetSelector(
              options.getMethodTargetSelector(), summaries,
              nativeSummaries.getIgnoredPackages(), cha);
      options.setSelector(ms);

      ClassTargetSelector cs =
          new BypassClassTargetSelector(
              options.getClassTargetSelector(),
              summaryClasses,
              cha,
              cha.getLoader(scope.getLoader(Atom.findOrCreateUnicodeAtom("Synthetic"))));
      options.setSelector(cs);
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } finally {
      if (null != s) {
        try {
          s.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
  }
 @Override
 public Set<Pattern> gatherSubPatterns(boolean includeOptionals) {
   Set<Pattern> ps = HashSetFactory.make(graphPattern.gatherSubPatterns());
   ps.add(this);
   return ps;
 }