@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; }
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; }
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; }
/* * @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; } } }
/** * @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); }
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; }
/** 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(); } }; }
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; }
/** 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); } } }
/** * 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; }