@Test public void testStaticInit() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope( TestConstants.WALA_TESTDATA, CallGraphTestUtil.REGRESSION_EXCLUSIONS); ClassHierarchy cha = ClassHierarchy.make(scope); Iterable<Entrypoint> entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints( scope, cha, "LstaticInit/TestStaticInit"); AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); CallGraph cg = CallGraphTestUtil.buildZeroCFA(options, new AnalysisCache(), cha, scope, false); boolean foundDoNothing = false; for (CGNode n : cg) { if (n.toString().contains("doNothing")) { foundDoNothing = true; break; } } Assert.assertTrue(foundDoNothing); options.setHandleStaticInit(false); cg = CallGraphTestUtil.buildZeroCFA(options, new AnalysisCache(), cha, scope, false); for (CGNode n : cg) { Assert.assertTrue(!n.toString().contains("doNothing")); } }
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 void addParamEdges(LocalPointerKey pk, CGNode node) { // get parameter position: value number - 1? int paramPos = pk.getValueNumber() - 1; // iterate over callers for (CGNode caller : cg) { // TODO we don't need to add the graph if null is passed // as the argument addSubgraphForNode(caller); IR ir = caller.getIR(); for (Iterator<CallSiteReference> iterator = ir.iterateCallSites(); iterator.hasNext(); ) { CallSiteReference call = iterator.next(); if (cg.getPossibleTargets(caller, call).contains(node)) { SSAAbstractInvokeInstruction[] callInstrs = ir.getCalls(call); for (int i = 0; i < callInstrs.length; i++) { SSAAbstractInvokeInstruction callInstr = callInstrs[i]; PointerKey actualPk = heapModel.getPointerKeyForLocal(caller, callInstr.getUse(paramPos)); assert containsNode(actualPk); assert containsNode(pk); addEdge(pk, actualPk); } } } } }
protected void unconditionallyAddConstraintsFromNode(CGNode node) { if (DEBUG) { System.err.println(("Visiting CGNode " + node)); } if (SSAPropagationCallGraphBuilder.PERIODIC_WIPE_SOFT_CACHES) { wipeCount++; if (wipeCount >= SSAPropagationCallGraphBuilder.WIPE_SOFT_CACHE_INTERVAL) { wipeCount = 0; ReferenceCleanser.clearSoftCaches(); } } IR ir = node.getIR(); debugPrintIR(ir); if (ir == null) { return; } DefUse du = node.getDU(); addNodeInstructionConstraints(node, ir, du); addNodePassthruExceptionConstraints(node, ir); }
/** check that the types of all instance keys are assignable to declared type of pointer key */ private void checkTypes(IntSet b) { assert PARANOID; if (b == null) return; if (!(pointerKey instanceof LocalPointerKey)) { return; } final LocalPointerKey lpk = (LocalPointerKey) pointerKey; CGNode node = lpk.getNode(); final IClassHierarchy cha = node.getClassHierarchy(); final IR ir = node.getIR(); if (ir == null) return; TypeInference ti = TypeInference.make(ir, false); final IClass type = ti.getType(lpk.getValueNumber()).getType(); if (type == null) return; // don't perform checking for exception variables if (cha.isAssignableFrom(cha.lookupClass(TypeReference.JavaLangThrowable), type)) { return; } b.foreach( new IntSetAction() { public void act(int x) { InstanceKey ik = instanceKeys.getMappedObject(x); IClass concreteType = ik.getConcreteType(); if (!cha.isAssignableFrom(type, concreteType)) { System.err.println("BOOM"); System.err.println(ir); System.err.println(lpk + " type " + type); System.err.println(ik + " type " + concreteType); Assertions.UNREACHABLE(); } } }); }
private boolean exceedsRecursionBound(Context baseContext, int curLevel) { if (curLevel > recursionBound) { return true; } // we just do a case analysis here. we might have to add cases later to // account for new types of context / recursion. CGNode callerNode = (CGNode) baseContext.get(ContextKey.CALLER); if (callerNode != null && exceedsRecursionBound(callerNode.getContext(), curLevel + 1)) { return true; } for (int i = 0; i < MAX_INTERESTING_PARAM; i++) { FilteredPointerKey.SingleInstanceFilter filter = (SingleInstanceFilter) baseContext.get(ContextKey.PARAMETERS[i]); if (filter != null) { InstanceKey ik = filter.getInstance(); if (ik instanceof ScopeMappingInstanceKey) { ik = ((ScopeMappingInstanceKey) ik).getBase(); } if (ik instanceof InstanceKeyWithNode) { if (exceedsRecursionBound( ((InstanceKeyWithNode) ik).getNode().getContext(), curLevel + 1)) { return true; } } } } return false; }
@Test public void testSystemProperties() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope( TestConstants.WALA_TESTDATA, CallGraphTestUtil.REGRESSION_EXCLUSIONS); ClassHierarchy cha = ClassHierarchy.make(scope); Iterable<Entrypoint> entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints( scope, cha, "LstaticInit/TestSystemProperties"); AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); SSAPropagationCallGraphBuilder builder = Util.makeZeroCFABuilder(options, new AnalysisCache(), cha, scope); CallGraph cg = builder.makeCallGraph(options); for (CGNode n : cg) { if (n.toString() .equals( "Node: < Application, LstaticInit/TestSystemProperties, main([Ljava/lang/String;)V > Context: Everywhere")) { boolean foundToCharArray = false; for (CGNode callee : Iterator2Iterable.make(cg.getSuccNodes(n))) { if (callee.getMethod().getName().toString().equals("toCharArray")) { foundToCharArray = true; break; } } Assert.assertTrue(foundToCharArray); break; } } }
public IR getIR(CGNode n) { // AnalysisOptions options = new AnalysisOptions(); IR ir = analysisCache .getSSACache() .findOrCreateIR(n.getMethod(), n.getContext(), options.getSSAOptions()); return ir; }
@Override public IMethod getCalleeTarget(CGNode caller, CallSiteReference site, IClass receiver) { IMethod target = base.getCalleeTarget(caller, site, receiver); if (target != null && target.getReference().equals(loadFileFunRef)) { Set<String> names = new HashSet<String>(); SSAInstruction call = caller.getIR() .getInstructions()[ caller.getIR().getCallInstructionIndices(site).intIterator().next()]; if (call.getNumberOfUses() > 1) { LocalPointerKey fileNameV = new LocalPointerKey(caller, call.getUse(1)); OrdinalSet<InstanceKey> ptrs = builder.getPointerAnalysis().getPointsToSet(fileNameV); for (InstanceKey k : ptrs) { if (k instanceof ConstantKey) { Object v = ((ConstantKey) k).getValue(); if (v instanceof String) { names.add((String) v); } } } if (names.size() == 1) { String str = names.iterator().next(); try { JavaScriptLoader cl = (JavaScriptLoader) builder.getClassHierarchy().getLoader(JavaScriptTypes.jsLoader); URL url = new URL(builder.getBaseURL(), str); if (!loadedFiles.contains(url)) { // try to open the input stream for the URL. if it fails, we'll get an IOException // and fall through to default case InputStream inputStream = url.openConnection().getInputStream(); inputStream.close(); JSCallGraphUtil.loadAdditionalFile(builder.getClassHierarchy(), cl, url); loadedFiles.add(url); IClass script = builder .getClassHierarchy() .lookupClass( TypeReference.findOrCreate(cl.getReference(), "L" + url.getFile())); return script.getMethod(JavaScriptMethods.fnSelector); } } catch (MalformedURLException e1) { // do nothing, fall through and return 'target' } catch (IOException e) { // do nothing, fall through and return 'target' } catch (RuntimeException e) { // do nothing, fall through and return 'target' } } } } return target; }
@SuppressWarnings("unused") public void run() throws UnsoundGraphException { Set<CGNode> allCalled = findAllCalledMethods(cg.getEntrypointNodes()); for (CGNode method : allCalled) { IMethod im = method.getMethod(); if (!im.isNative() && !im.isAbstract() && !im.isSynthetic()) { ControlFlowGraph<SSAInstruction, IExplodedBasicBlock> cfg = getPruned(method, null); } } }
/** * @see * com.ibm.wala.ipa.callgraph.propagation.rta.RTAContextInterpreter#understands(com.ibm.wala.ipa.callgraph.CGNode) */ @Override public boolean understands(CGNode node) { if (node == null) { throw new IllegalArgumentException("node is null"); } if (!(node.getContext() instanceof GetMethodContext)) { return false; } MethodReference mRef = node.getMethod().getReference(); return mRef.equals(GET_METHOD) || mRef.equals(GET_DECLARED_METHOD); }
private FilteredPointerKey.TypeFilter getFilter(CGNode target) { FilteredPointerKey.TypeFilter filter = (FilteredPointerKey.TypeFilter) target.getContext().get(ContextKey.PARAMETERS[0]); if (filter != null) { return filter; } else { // the context does not select a particular concrete type for the // receiver. IClass C = getReceiverClass(target.getMethod()); return new FilteredPointerKey.SingleClassFilter(C); } }
private static void printDetails(CGNode method, ExplodedControlFlowGraph cfg, FlowGraph pruned) { int deletedEdges = 0; int originalEdges = 0; for (IExplodedBasicBlock node : cfg) { originalEdges += cfg.getSuccNodeCount(node); Iterator<IExplodedBasicBlock> it = cfg.getSuccNodes(node); int srcNum = node.getNumber(); while (it.hasNext()) { IExplodedBasicBlock dst = it.next(); int dstNum = dst.getNumber(); if (pruned.hasEdge(srcNum, dstNum)) { deletedEdges++; } } } DecimalFormat df = new DecimalFormat("00.00"); double percent = ((double) deletedEdges / (double) originalEdges) * 100.0; Log.info( "EXC: " + df.format(percent) + "% - edges: " + originalEdges + " deleted: " + deletedEdges + " - " + edu.kit.joana.deprecated.jsdg.util.Util.methodName(method.getMethod())); }
@Override public PointerKey getPointerKeyForLocal(CGNode node, int valueNumber) { if (!node.getMethod().isStatic() && valueNumber == 1) { return delegate.getFilteredPointerKeyForLocal(node, valueNumber, getFilter(node)); } else { return delegate.getPointerKeyForLocal(node, valueNumber); } }
/** * Add constraints to represent the flow of exceptions to the exceptional return value for this * node */ protected void addNodePassthruExceptionConstraints(CGNode node, IR ir) { // add constraints relating to thrown exceptions that reach the exit block. List<ProgramCounter> peis = SSAPropagationCallGraphBuilder.getIncomingPEIs(ir, ir.getExitBlock()); PointerKey exception = heapModel.getPointerKeyForExceptionalReturnValue(node); IClass c = node.getClassHierarchy().lookupClass(TypeReference.JavaLangThrowable); addExceptionDefConstraints(ir, node, peis, exception, Collections.singleton(c)); }
public void addNonEntryReportData( final String sourceFilePath, final Set<Integer> lines, final CGNode cgNode) { JavaFileData dataForNode = reportData.getJavaFileDataForCGNode(cgNode); if (dataForNode == null) { dataForNode = reportData.addNewJavaFileData(sourceFilePath, cgNode.getMethod().getDeclaringClass()); } dataForNode.addLineNumbersForCGNode(cgNode, lines); }
@Override public IMethod getCalleeTarget(CGNode caller, CallSiteReference site, IClass receiver) { if (site.getDeclaredTarget().equals(JavaScriptMethods.ctorReference)) { assert cha.isSubclassOf(receiver, cha.lookupClass(JavaScriptTypes.Root)); IR callerIR = caller.getIR(); SSAAbstractInvokeInstruction callStmts[] = callerIR.getCalls(site); assert callStmts.length == 1; int nargs = callStmts[0].getNumberOfParameters(); return findOrCreateConstructorMethod(callerIR, callStmts[0], receiver, nargs - 1); } else { return base.getCalleeTarget(caller, site, receiver); } }
@Override public Iterator<NewSiteReference> iterateNewSites(CGNode node) { if (node == null) { throw new IllegalArgumentException("node is null"); } assert understands(node); GetMethodContext context = (GetMethodContext) node.getContext(); TypeReference tr = context.getType().getTypeReference(); if (tr != null) { return new NonNullSingletonIterator<NewSiteReference>(NewSiteReference.make(0, tr)); } return EmptyIterator.instance(); }
/* (non-Javadoc) * @see edu.kit.ipd.wala.ExceptionPrunedCFG#getPruned(com.ibm.wala.ipa.callgraph.CGNode) */ @Override public ControlFlowGraph<SSAInstruction, IExplodedBasicBlock> getPruned( CGNode method, IProgressMonitor progress) throws UnsoundGraphException { FlowGraph graph = cg2graph.get(method); ExplodedControlFlowGraph origCfg = cg2origcfg.get(method); if (graph == null) { if (DEBUG) { String fileName = method.getMethod().getSignature(); fileName = fileName.replace('/', '.'); System.out.println("--- Starting " + fileName + " ---"); MethodCFG mCFG = new MethodCFG(method, ignoreExceptions); if (mCFG.init(cache)) { mCFG.write(mCFG.getOriginalGraph(), "out/" + fileName + ".dot"); System.out.println( "Exceptions in original graph: " + mCFG.getOriginalGraph().countExceptions()); mCFG.purgeExceptions(); graph = mCFG.getGraph(); mCFG.write(graph, "out/" + fileName + ".filter.dot"); System.out.println("Exceptions in final graph: " + graph.countExceptions()); cg2graph.put(method, graph); origCfg = mCFG.getECFG(); cg2origcfg.put(method, origCfg); } } else { MethodCFG mCFG = new MethodCFG(method, ignoreExceptions); if (mCFG.init(cache)) { mCFG.purgeExceptions(); graph = mCFG.getGraph(); cg2graph.put(method, graph); origCfg = mCFG.getECFG(); cg2origcfg.put(method, origCfg); } } printDetails(method, origCfg, graph); } if (graph != null) { IgnoreEdgeListFilter filter = new IgnoreEdgeListFilter(origCfg, graph); PrunedCFG<SSAInstruction, IExplodedBasicBlock> pCFG = PrunedCFG.make(origCfg, filter); return pCFG; } else { return null; } }
public void start(Class<? extends ICostComputer<ICostResult>> costComputerType) throws InstantiationException, IllegalAccessException, IllegalArgumentException, WalaException, IOException, SecurityException, InvocationTargetException, NoSuchMethodException { this.costComputer = costComputerType .getDeclaredConstructor(JVMModel.class) .newInstance(specification.getJvmModel()); LinkedList<CGNode> entryCGNodes = specification.getEntryPointCGNodes(); for (CGNode entryNode : entryCGNodes) { // OutputPrinter.printInfo("Starting entry node " + entryNode.getMethod().toString()); ICostResult results = new CGNodeAnalyzer(entryNode, costComputer).analyzeNode(); // ICostResult results = new // CostComputerMemory(specification.getJvmModel()).dfsVisit(entryNode); // Test code CostResultMemory memRes = (CostResultMemory) results; OutputPrinter.printInfo( "Worst case allocation for " + entryNode.getMethod().toString() + ":\t" + results.getCostScalar()); for (Entry<TypeName, Integer> i : memRes.aggregatedCountByTypename.entrySet()) { OutputPrinter.printInfo( "\t TYPE_NAME\t" + i.getKey().toString() + "\tCOUNT " + i.getValue()); } } /* This is move to the program. if ( specification.getTypeOfAnalysisPerformed() != AnalysisType.ALLOCATIONS) { stackAnalyzer.analyze(); } if ( specification.getShouldGenerateAnalysisReports() == true) { ReportGenerator gen = new ReportGenerator(); gen.Generate(AnalysisResults.getAnalysisResults().getReportEntries()); }*/ }
/** * @see * com.ibm.wala.ipa.callgraph.propagation.SSAContextInterpreter#getIR(com.ibm.wala.ipa.callgraph.CGNode) */ @Override public IR getIR(CGNode node) { if (node == null) { throw new IllegalArgumentException("node is null"); } assert understands(node); if (DEBUG) { System.err.println("generating IR for " + node); } IMethod method = node.getMethod(); GetMethodContext context = (GetMethodContext) node.getContext(); Map<Integer, ConstantValue> constants = HashMapFactory.make(); if (method.getReference().equals(GET_METHOD)) { Atom name = Atom.findOrCreateAsciiAtom(context.getName()); SSAInstruction instrs[] = makeGetMethodStatements(context, constants, name); return new SyntheticIR( method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), constants); } if (method.getReference().equals(GET_DECLARED_METHOD)) { Atom name = Atom.findOrCreateAsciiAtom(context.getName()); SSAInstruction instrs[] = makeGetDeclaredMethodStatements(context, constants, name); return new SyntheticIR( method, context, new InducedCFG(instrs, method, context), instrs, SSAOptions.defaultOptions(), constants); } Assertions.UNREACHABLE("Unexpected method " + node); return null; }
/** * Compute the set of PointerKeys each statement refs.Be careful to avoid eager PDG construction * here! That means .. don't iterate over SDG statements! */ public static Map<Statement, Set<PointerKey>> scanForRef( SDG sdg, PointerAnalysis pa, ModRef modRef) { if (pa == null) { throw new IllegalArgumentException("null pa"); } ExtendedHeapModel h = new DelegatingExtendedHeapModel(pa.getHeapModel()); Map<Statement, Set<PointerKey>> result = HashMapFactory.make(); for (CGNode n : sdg.getCallGraph()) { IR ir = n.getIR(); if (ir != null) { for (int i = 0; i < ir.getInstructions().length; i++) { SSAInstruction st = ir.getInstructions()[i]; if (st != null) { Set<PointerKey> mod = modRef.getRef(n, h, pa, st, null); if (!mod.isEmpty()) { NormalStatement normal = new NormalStatement(n, i); result.put(normal, mod); } } } } } return result; }
@Override public Context getCalleeTarget( CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] actualParameters) { Context baseContext = base.getCalleeTarget(caller, site, callee, actualParameters); final boolean exceedsRecursionBound = exceedsRecursionBound(baseContext, 0); if (!exceedsRecursionBound) { return baseContext; } else if (callee instanceof JavaScriptConstructor) { // for constructors, we want to keep some basic context sensitivity to // avoid horrible imprecision return new CallStringContext(new CallString(site, caller.getMethod())); } else { // TODO somehow k-limit more smartly? return Everywhere.EVERYWHERE; } }
/** * add nodes for parameters and return values * * @param node */ private void addNodesForParameters(CGNode node) { // TODO Auto-generated method stub IR ir = node.getIR(); TypeInference ti = TypeInference.make(ir, false); SymbolTable symbolTable = ir.getSymbolTable(); for (int i = 0; i < symbolTable.getNumberOfParameters(); i++) { int parameter = symbolTable.getParameter(i); TypeAbstraction t = ti.getType(parameter); if (t != null) { PointerKey paramPk = heapModel.getPointerKeyForLocal(node, parameter); addNode(paramPk); params.put(paramPk, node); } } addNode(heapModel.getPointerKeyForReturnValue(node)); addNode(heapModel.getPointerKeyForExceptionalReturnValue(node)); }
private static List<Pair<CGNode, SSACheckCastInstruction>> findFailingCasts( CallGraph cg, DemandRefinementPointsTo dmp) { final IClassHierarchy cha = dmp.getClassHierarchy(); List<Pair<CGNode, SSACheckCastInstruction>> failing = new ArrayList<Pair<CGNode, SSACheckCastInstruction>>(); int numSafe = 0, numMightFail = 0; outer: for (Iterator<? extends CGNode> nodeIter = cg.iterator(); nodeIter.hasNext(); ) { CGNode node = nodeIter.next(); TypeReference declaringClass = node.getMethod().getReference().getDeclaringClass(); // skip library classes if (declaringClass.getClassLoader().equals(ClassLoaderReference.Primordial)) { continue; } IR ir = node.getIR(); if (ir == null) continue; SSAInstruction[] instrs = ir.getInstructions(); for (int i = 0; i < instrs.length; i++) { if (numSafe + numMightFail > MAX_CASTS) break outer; SSAInstruction instruction = instrs[i]; if (instruction instanceof SSACheckCastInstruction) { SSACheckCastInstruction castInstr = (SSACheckCastInstruction) instruction; final TypeReference[] declaredResultTypes = castInstr.getDeclaredResultTypes(); boolean primOnly = true; for (TypeReference t : declaredResultTypes) { if (!t.isPrimitiveType()) { primOnly = false; } } if (primOnly) { continue; } System.err.println("CHECKING " + castInstr + " in " + node.getMethod()); PointerKey castedPk = heapModel.getPointerKeyForLocal(node, castInstr.getUse(0)); Predicate<InstanceKey> castPred = new Predicate<InstanceKey>() { @Override public boolean test(InstanceKey ik) { TypeReference ikTypeRef = ik.getConcreteType().getReference(); for (TypeReference t : declaredResultTypes) { if (cha.isAssignableFrom(cha.lookupClass(t), cha.lookupClass(ikTypeRef))) { return true; } } return false; } }; long startTime = System.currentTimeMillis(); Pair<PointsToResult, Collection<InstanceKey>> queryResult = dmp.getPointsTo(castedPk, castPred); long runningTime = System.currentTimeMillis() - startTime; System.err.println("running time: " + runningTime + "ms"); final FieldRefinePolicy fieldRefinePolicy = dmp.getRefinementPolicy().getFieldRefinePolicy(); switch (queryResult.fst) { case SUCCESS: System.err.println("SAFE: " + castInstr + " in " + node.getMethod()); if (fieldRefinePolicy instanceof ManualFieldPolicy) { ManualFieldPolicy hackedFieldPolicy = (ManualFieldPolicy) fieldRefinePolicy; System.err.println(hackedFieldPolicy.getHistory()); } System.err.println("TRAVERSED " + dmp.getNumNodesTraversed() + " nodes"); numSafe++; break; case NOMOREREFINE: if (queryResult.snd != null) { System.err.println( "MIGHT FAIL: no more refinement possible for " + castInstr + " in " + node.getMethod()); } else { System.err.println( "MIGHT FAIL: exceeded budget for " + castInstr + " in " + node.getMethod()); } failing.add(Pair.make(node, castInstr)); numMightFail++; break; case BUDGETEXCEEDED: System.err.println( "MIGHT FAIL: exceeded budget for " + castInstr + " in " + node.getMethod()); failing.add(Pair.make(node, castInstr)); numMightFail++; break; default: Assertions.UNREACHABLE(); } } } // break outer; } System.err.println("TOTAL SAFE: " + numSafe); System.err.println("TOTAL MIGHT FAIL: " + numMightFail); return failing; }