@Override public Iterator<CallSiteReference> getPossibleSites(CGNode src, CGNode target) { if (!(keep.contains(src) && keep.contains(target)) || removedEdge(src, target)){ return null; } return cg.getPossibleSites(src, target); }
@Override public Iterator<CallSiteReference> getPossibleSites(CGNode src, CGNode target) { if (!(keep.contains(src) && keep.contains(target)) || removedEdge(src, target)){ return null; } return cg.getPossibleSites(src, target); }
@Override public Iterator<CallSiteReference> getPossibleSites(CGNode src, CGNode target) { return ((containsNode(src) && containsNode(target)) ? cg.getPossibleSites(src, target) : null); }
@Override public Iterator<CallSiteReference> getPossibleSites(CGNode src, CGNode target) { return ((containsNode(src) && containsNode(target)) ? cg.getPossibleSites(src, target) : null); }
@Override public UnaryOperator<BitVectorVariable> getEdgeTransferFunction(CGNode dst, CGNode src) { /* * Note, that dst and src are swapped. For the data-flow-analysis we use * called -> caller, but for the call graph we need caller -> called. */ Iterator<CallSiteReference> callsites = cg.getPossibleSites(src, dst); BitVector filtered = new BitVector(transformer.getValues().getSize()); if (callsites.hasNext()) { CallSiteReference callsite = callsites.next(); Set<TypeReference> caught = new LinkedHashSet<>(intraResult.getAnalysis(src).getCaughtExceptions(callsite)); while (callsites.hasNext()) { callsite = callsites.next(); caught.retainAll(intraResult.getAnalysis(src).getCaughtExceptions(callsite)); } filtered = transformer.computeBitVector(caught); return new BitVectorMinusVector(filtered); } else { // This case should not happen, as we should only get src, dst pairs, // which represent an edge in the call graph. For each edge in the call // graph should be at least one call site. throw new RuntimeException("Internal Error: Got call graph edge without call site."); } } }
@Override public UnaryOperator<BitVectorVariable> getEdgeTransferFunction(CGNode dst, CGNode src) { /* * Note, that dst and src are swapped. For the data-flow-analysis we use * called -> caller, but for the call graph we need caller -> called. */ Iterator<CallSiteReference> callsites = cg.getPossibleSites(src, dst); BitVector filtered = new BitVector(transformer.getValues().getSize()); if (callsites.hasNext()) { CallSiteReference callsite = callsites.next(); Set<TypeReference> caught = new LinkedHashSet<>(intraResult.getAnalysis(src).getCaughtExceptions(callsite)); while (callsites.hasNext()) { callsite = callsites.next(); caught.retainAll(intraResult.getAnalysis(src).getCaughtExceptions(callsite)); } filtered = transformer.computeBitVector(caught); return new BitVectorMinusVector(filtered); } else { // This case should not happen, as we should only get src, dst pairs, // which represent an edge in the call graph. For each edge in the call // graph should be at least one call site. throw new RuntimeException("Internal Error: Got call graph edge without call site."); } } }
@Override public Set<CallerSiteContext> getPotentialCallers(PointerKey formalPk) { CGNode callee = null; if (formalPk instanceof LocalPointerKey) { callee = ((LocalPointerKey) formalPk).getNode(); } else if (formalPk instanceof ReturnValueKey) { callee = ((ReturnValueKey) formalPk).getNode(); } else { throw new IllegalArgumentException("formalPk must represent a local"); } Set<CallerSiteContext> ret = callerCache.get(callee); if (ret == null) { ret = HashSetFactory.make(); for (CGNode caller : Iterator2Iterable.make(cg.getPredNodes(callee))) { for (CallSiteReference call : Iterator2Iterable.make(cg.getPossibleSites(caller, callee))) { ret.add(new CallerSiteContext(caller, call)); } } callerCache.put(callee, ret); } return ret; }
@Override public Set<CallerSiteContext> getPotentialCallers(PointerKey formalPk) { CGNode callee = null; if (formalPk instanceof LocalPointerKey) { callee = ((LocalPointerKey) formalPk).getNode(); } else if (formalPk instanceof ReturnValueKey) { callee = ((ReturnValueKey) formalPk).getNode(); } else { throw new IllegalArgumentException("formalPk must represent a local"); } Set<CallerSiteContext> ret = callerCache.get(callee); if (ret == null) { ret = HashSetFactory.make(); for (CGNode caller : Iterator2Iterable.make(cg.getPredNodes(callee))) { for (CallSiteReference call : Iterator2Iterable.make(cg.getPossibleSites(caller, callee))) { ret.add(new CallerSiteContext(caller, call)); } } callerCache.put(callee, ret); } return ret; }
@Override public Iterator<Pair<CGNode, NewSiteReference>> getCreationSites(CallGraph CG) { MethodReference ctorRef = JavaScriptMethods.makeCtorReference(JavaScriptTypes.Function); Set<CGNode> f = CG.getNodes(ctorRef); CGNode ctor = null; for(CGNode n : f) { JavaScriptConstructor c = (JavaScriptConstructor) n.getMethod(); if (c.constructedType().equals(klass)) { ctor = n; break; } } // built in objects if (ctor == null) { return EmptyIterator.instance(); } Iterator<CGNode> callers = CG.getPredNodes(ctor); CGNode caller = callers.next(); assert !callers.hasNext(); Iterator<CallSiteReference> sites = CG.getPossibleSites(caller, ctor); CallSiteReference site = sites.next(); assert !sites.hasNext() : caller + " --> " + ctor + " @ " + site + " and " + sites.next() + '\n' + caller.getIR(); return NonNullSingletonIterator.make(Pair.make(caller, NewSiteReference.make(site.getProgramCounter(), klass.getReference()))); }
@Override public Iterator<Pair<CGNode, NewSiteReference>> getCreationSites(CallGraph CG) { MethodReference ctorRef = JavaScriptMethods.makeCtorReference(JavaScriptTypes.Function); Set<CGNode> f = CG.getNodes(ctorRef); CGNode ctor = null; for(CGNode n : f) { JavaScriptConstructor c = (JavaScriptConstructor) n.getMethod(); if (c.constructedType().equals(klass)) { ctor = n; break; } } // built in objects if (ctor == null) { return EmptyIterator.instance(); } Iterator<CGNode> callers = CG.getPredNodes(ctor); CGNode caller = callers.next(); assert !callers.hasNext(); Iterator<CallSiteReference> sites = CG.getPossibleSites(caller, ctor); CallSiteReference site = sites.next(); assert !sites.hasNext() : caller + " --> " + ctor + " @ " + site + " and " + sites.next() + '\n' + caller.getIR(); return NonNullSingletonIterator.make(Pair.make(caller, NewSiteReference.make(site.getProgramCounter(), klass.getReference()))); }
protected void checkEdges(CallGraph staticCG, Predicate<MethodReference> filter) throws IOException { final Set<Pair<CGNode,CGNode>> edges = HashSetFactory.make(); check(staticCG, (staticCG1, caller, calleeRef) -> { Set<CGNode> nodes = staticCG1.getNodes(calleeRef); Assert.assertEquals("expected one node for " + calleeRef, 1, nodes.size()); CGNode callee = nodes.iterator().next(); Assert.assertTrue("no edge for " + caller + " --> " + callee, staticCG1.getPossibleSites(caller, callee).hasNext()); Pair<CGNode,CGNode> x = Pair.make(caller, callee); if (edges.add(x)) { System.err.println("found expected edge " + caller + " --> " + callee); } }, filter); }
private static Pair<CGNode, NewSiteReference> map(CallGraph CG, Pair<CGNode, NewSiteReference> ptr) { CGNode n = ptr.fst; if (! (n.getMethod() instanceof JavaScriptConstructor)) { return ptr; } Iterator<CGNode> preds = CG.getPredNodes(n); if (! preds.hasNext()) { return ptr; } CGNode caller = preds.next(); assert !preds.hasNext() : n; Iterator<CallSiteReference> sites = CG.getPossibleSites(caller, n); CallSiteReference site = sites.next(); assert ! sites.hasNext(); return Pair.make(caller, new NewSiteReference(site.getProgramCounter(), ptr.snd.getDeclaredType())); }
@Test public void testFinalize() throws ClassHierarchyException, IllegalArgumentException, CancelException, IOException { AnalysisScope scope = CallGraphTestUtil.makeJ2SEAnalysisScope(TestConstants.WALA_TESTDATA, CallGraphTestUtil.REGRESSION_EXCLUSIONS); ClassHierarchy cha = ClassHierarchyFactory.make(scope); Iterable<Entrypoint> entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, "Lfinalizers/Finalizers"); AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); CallGraph cg = CallGraphTestUtil.buildZeroCFA(options, new AnalysisCacheImpl(), cha, scope, false); // Find node corresponding to finalize TypeReference t = TypeReference.findOrCreate(ClassLoaderReference.Application, "Lfinalizers/Finalizers"); MethodReference m = MethodReference.findOrCreate(t, "finalize", "()V"); Assert.assertTrue("expect finalizer node", cg.getNodes(m).iterator().hasNext()); CGNode node = cg.getNodes(m).iterator().next(); // Check it's reachable from root Assert.assertTrue("should have call site from root", cg.getPossibleSites(cg.getFakeRootNode(), node).hasNext()); } }
Assert.assertTrue("should have call site from main to Interface1.silly", cg.getPossibleSites(mnode, t1node).hasNext()); Assert.assertTrue("should have call site from main to Interface2.silly", cg.getPossibleSites(mnode, t2node).hasNext()); Assert.assertTrue("should have call site from main to Test3.silly", cg.getPossibleSites(mnode, ttnode).hasNext());
private Collection<Statement> findTargetStatement(CallGraph CG) { final Collection<Statement> ss = HashSetFactory.make(); for(CGNode n : getNodes(CG, "suffix:_slice_target_fn")) { for(CGNode caller : Iterator2Iterable.make(CG.getPredNodes(n))) { for(CallSiteReference site : Iterator2Iterable.make(CG.getPossibleSites(caller, n))) { caller.getIR().getCallInstructionIndices(site).foreach(x -> ss.add(new NormalStatement(caller, x))); } } } return ss; } }