/** * @param m a method reference * @return a SyntheticMethod corresponding to m; or null if none is available. */ protected SyntheticMethod findOrCreateSyntheticMethod(MethodReference m, boolean isStatic) { if (syntheticMethods.containsKey(m)) { return syntheticMethods.get(m); } else { MethodSummary summ = null; if (canIgnore(m)) { TypeReference T = m.getDeclaringClass(); IClass C = cha.lookupClass(T); if (C == null) { // did not load class; don't try to create a synthetic method syntheticMethods.put(m, null); return null; } summ = generateNoOp(m, isStatic); } else { summ = findSummary(m); } if (summ != null) { TypeReference T = m.getDeclaringClass(); IClass C = cha.lookupClass(T); if (C == null) { syntheticMethods.put(m, null); return null; } SummarizedMethod n = new SummarizedMethod(m, summ, C); syntheticMethods.put(m, n); return n; } else { syntheticMethods.put(m, null); return null; } } }
@Test public void testClassAnnotations3() throws Exception { TypeReference typeRef = TypeReference.findOrCreate( ClassLoaderReference.Application, "Lannotations/AnnotatedClass3"); IClass klass = cha.lookupClass(typeRef); Assert.assertNotNull(klass); ShrikeClass shrikeClass = (ShrikeClass) klass; Collection<Annotation> classAnnotations = shrikeClass.getAnnotations(true); Assert.assertEquals( "[Annotation type <Application,Lannotations/AnnotationWithParams> {strParam=classStrParam}]", classAnnotations.toString()); MethodReference methodRefUnderTest = MethodReference.findOrCreate(typeRef, Selector.make("foo()V")); IMethod methodUnderTest = cha.resolveMethod(methodRefUnderTest); Assert.assertNotNull(methodRefUnderTest.toString() + " not found", methodUnderTest); Assert.assertTrue(methodUnderTest instanceof ShrikeCTMethod); ShrikeCTMethod shrikeCTMethodUnderTest = (ShrikeCTMethod) methodUnderTest; Collection<Annotation> runtimeInvisibleAnnotations = shrikeCTMethodUnderTest.getAnnotations(true); Assert.assertEquals( "[Annotation type <Application,Lannotations/AnnotationWithParams> {enumParam=EnumElementValue [type=Lannotations/AnnotationEnum;, val=VAL1], strArrParam=ArrayElementValue [vals=[biz, boz]], annotParam=AnnotationElementValue [type=Lannotations/AnnotationWithSingleParam;, elementValues={value=sdfevs}], strParam=sdfsevs, intParam=25, klassParam=Ljava/lang/Integer;}]", runtimeInvisibleAnnotations.toString()); }
/** 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(); } } }); }
@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); } }
/** * @param type * @return a TypeAbstraction object representing this type. We just use ConeTypes by default, * since we don't propagate information allowing us to distinguish between points and cones * yet. */ protected TypeAbstraction typeRef2TypeAbstraction(IClassHierarchy cha, TypeReference type) { IClass klass = cha.lookupClass(type); if (klass != null) { return new ConeType(klass); } Assertions.UNREACHABLE(type.toString()); return null; }
/** * Return a view of an {@link IClassHierarchy} as a {@link Graph}, with edges from classes to * immediate subtypes */ public static Graph<IClass> typeHierarchy2Graph(IClassHierarchy cha) throws WalaException { Graph<IClass> result = SlowSparseNumberedGraph.make(); for (IClass c : cha) { result.addNode(c); } for (IClass c : cha) { for (IClass x : cha.getImmediateSubclasses(c)) { result.addEdge(c, x); } if (c.isInterface()) { for (IClass x : cha.getImplementors(c.getReference())) { result.addEdge(c, x); } } } return result; }
/** * @param method * @return the receiver class for this method. */ private IClass getReceiverClass(IMethod method) { TypeReference formalType = method.getParameterType(0); IClass C = cha.lookupClass(formalType); if (method.isStatic()) { Assertions.UNREACHABLE("asked for receiver of static method " + method); } if (C == null) { Assertions.UNREACHABLE("no class found for " + formalType + " recv of " + method); } return C; }
/** * Usage: ScopeFileCallGraph -sourceDir file_path -mainClass class_name * * <p>If given -mainClass, uses main() method of class_name as entrypoint. Class name should start * with an 'L'. * * <p>Example args: -sourceDir /tmp/srcTest -mainClass LFoo */ public static void main(String[] args) throws ClassHierarchyException, IllegalArgumentException, CallGraphBuilderCancelException, IOException { long start = System.currentTimeMillis(); Properties p = CommandLine.parse(args); String sourceDir = p.getProperty("sourceDir"); String mainClass = p.getProperty("mainClass"); AnalysisScope scope = new JavaSourceAnalysisScope(); // add standard libraries to scope String[] stdlibs = WalaProperties.getJ2SEJarFiles(); for (int i = 0; i < stdlibs.length; i++) { scope.addToScope(ClassLoaderReference.Primordial, new JarFile(stdlibs[i])); } // add the source directory scope.addToScope( JavaSourceAnalysisScope.SOURCE, new SourceDirectoryTreeModule(new File(sourceDir))); // build the class hierarchy IClassHierarchy cha = ClassHierarchy.make(scope, new ECJClassLoaderFactory(scope.getExclusions())); System.out.println(cha.getNumberOfClasses() + " classes"); System.out.println(Warnings.asString()); Warnings.clear(); AnalysisOptions options = new AnalysisOptions(); Iterable<Entrypoint> entrypoints = Util.makeMainEntrypoints(JavaSourceAnalysisScope.SOURCE, cha, new String[] {mainClass}); options.setEntrypoints(entrypoints); // you can dial down reflection handling if you like // options.setReflectionOptions(ReflectionOptions.NONE); AnalysisCache cache = new AnalysisCache(AstIRFactory.makeDefaultFactory()); // CallGraphBuilder builder = new ZeroCFABuilderFactory().make(options, cache, cha, scope, // false); CallGraphBuilder builder = new ZeroOneContainerCFABuilderFactory().make(options, cache, cha, scope, false); System.out.println("building call graph..."); CallGraph cg = builder.makeCallGraph(options, null); long end = System.currentTimeMillis(); System.out.println("done"); System.out.println("took " + (end - start) + "ms"); System.out.println(CallGraphStats.getStats(cg)); }
private IMethod findOrCreateConstructorMethod( IR callerIR, SSAAbstractInvokeInstruction callStmt, IClass receiver, int nargs) { if (receiver.getReference().equals(JavaScriptTypes.Object)) return makeObjectConstructor(receiver, nargs); else if (receiver.getReference().equals(JavaScriptTypes.Array)) return makeArrayConstructor(receiver, nargs); else if (receiver.getReference().equals(JavaScriptTypes.StringObject)) return makeValueConstructor(receiver, nargs, ""); else if (receiver.getReference().equals(JavaScriptTypes.BooleanObject)) { assert nargs == 1; return makeValueConstructor(receiver, nargs, null); } else if (receiver.getReference().equals(JavaScriptTypes.NumberObject)) return makeValueConstructor(receiver, nargs, new Integer(0)); else if (receiver.getReference().equals(JavaScriptTypes.Function)) return makeFunctionConstructor(callerIR, callStmt, receiver, nargs); else if (cha.isSubclassOf(receiver, cha.lookupClass(JavaScriptTypes.CodeBody))) return makeFunctionObjectConstructor(receiver, nargs); else { return null; } }
/** @return Map: IClass -> Integer, the number of allocation sites for each type. */ private Map<IClass, Integer> countAllocsByType(CGNode node) { Map<IClass, Integer> count = HashMapFactory.make(); for (Iterator it = contextInterpreter.iterateNewSites(node); it.hasNext(); ) { NewSiteReference n = (NewSiteReference) it.next(); IClass alloc = cha.lookupClass(n.getDeclaredType()); if (alloc != null) { Integer old = count.get(alloc); if (old == null) { count.put(alloc, new Integer(1)); } else { count.put(alloc, new Integer(old.intValue() + 1)); } } } return count; }
private void testClassAnnotations( TypeReference typeUnderTest, Collection<Annotation> expectedRuntimeInvisibleAnnotations, Collection<Annotation> expectedRuntimeVisibleAnnotations) throws IOException, ClassHierarchyException, InvalidClassFileException { IClass classUnderTest = cha.lookupClass(typeUnderTest); Assert.assertNotNull(typeUnderTest.toString() + " not found", classUnderTest); Assert.assertTrue(classUnderTest instanceof ShrikeClass); ShrikeClass shrikeClassUnderTest = (ShrikeClass) classUnderTest; Collection<Annotation> runtimeInvisibleAnnotations = shrikeClassUnderTest.getRuntimeInvisibleAnnotations(); assertEqualCollections(expectedRuntimeInvisibleAnnotations, runtimeInvisibleAnnotations); Collection<Annotation> runtimeVisibleAnnotations = shrikeClassUnderTest.getRuntimeVisibleAnnotations(); assertEqualCollections(expectedRuntimeVisibleAnnotations, runtimeVisibleAnnotations); }
public InstanceKey getInstanceKeyForAllocation(CGNode node, NewSiteReference allocation) { if (allocation == null) { throw new IllegalArgumentException("allocation is null"); } TypeReference t = allocation.getDeclaredType(); IClass C = cha.lookupClass(t); if (C != null && isInteresting(C)) { if (smushMany()) { if (exceedsSmushLimit(C, node)) { return smushed.getInstanceKeyForAllocation(node, allocation); } else { return siteBased.getInstanceKeyForAllocation(node, allocation); } } else { return siteBased.getInstanceKeyForAllocation(node, allocation); } } else { return classBased.getInstanceKeyForAllocation(node, allocation); } }
public static void addJ2EEBypassLogic( AnalysisOptions options, AnalysisScope scope, DeploymentMetaData dmd, IClassHierarchy cha, ReceiverTypeInferenceCache typeInference) { if (cha == null) { throw new IllegalArgumentException("cha is null"); } MethodTargetSelector ms = new J2EEMethodTargetSelector( scope, options.getMethodTargetSelector(), dmd, cha, typeInference); options.setSelector(ms); ClassTargetSelector cs = new J2EEClassTargetSelector( options.getClassTargetSelector(), dmd, cha, cha.getLoader(scope.getLoader(Atom.findOrCreateUnicodeAtom("Synthetic")))); options.setSelector(cs); }
/** * 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); } } }
/* * @see com.ibm.wala.classLoader.IClass#getMethod(com.ibm.wala.classLoader.Selector) */ @Override public IMethod getMethod(Selector sig) { return cha.lookupClass(getClassLoader().getLanguage().getRootType()).getMethod(sig); }
// 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(); } } } }
/** * Generate a {@link MethodSummary} which is the "standard" representation of a method that does * nothing. Subclasses may override this method to implement alternative semantics concerning what * "do nothing" means. */ public MethodSummary generateNoOp(MethodReference m, boolean isStatic) { Language l = cha.resolveMethod(m).getDeclaringClass().getClassLoader().getLanguage(); return new NoOpSummary(l, m, isStatic); }
private IMethod makeFunctionConstructor( IR callerIR, SSAAbstractInvokeInstruction callStmt, IClass cls, int nargs) { SymbolTable ST = callerIR.getSymbolTable(); if (nargs == 0) { return makeFunctionConstructor(cls, cls); } else if (nargs == 1) { if (ST.isStringConstant(callStmt.getUse(1))) { TypeReference ref = TypeReference.findOrCreate( JavaScriptTypes.jsLoader, TypeName.string2TypeName((String) ST.getStringValue(callStmt.getUse(1)))); if (DEBUG) { System.err.println( ("ctor type name is " + (String) ST.getStringValue(callStmt.getUse(1)))); } IClass cls2 = cha.lookupClass(ref); if (cls2 != null) { return makeFunctionConstructor(cls, cls2); } } return makeFunctionConstructor(cls, cls); } else { assert nargs > 1; JavaScriptLoader cl = (JavaScriptLoader) cha.getLoader(JavaScriptTypes.jsLoader); for (int i = 1; i < callStmt.getNumberOfUses(); i++) if (!ST.isStringConstant(callStmt.getUse(i))) return makeFunctionConstructor(cls, cls); StringBuffer fun = new StringBuffer("function _fromctor ("); for (int j = 1; j < callStmt.getNumberOfUses() - 1; j++) { if (j != 1) fun.append(","); fun.append(ST.getStringValue(callStmt.getUse(j))); } fun.append(") {"); fun.append(ST.getStringValue(callStmt.getUse(callStmt.getNumberOfUses() - 1))); fun.append("}"); try { String fileName = "ctor$" + ++ctorCount; File f = new File(System.getProperty("java.io.tmpdir") + File.separator + fileName); FileWriter FO = new FileWriter(f); FO.write(fun.toString()); FO.close(); Set<String> fnNames = JSCallGraphUtil.loadAdditionalFile(cha, cl, fileName, f.toURI().toURL()); IClass fcls = null; for (String nm : fnNames) { if (nm.endsWith("_fromctor")) { fcls = cl.lookupClass(nm, cha); } } assert fcls != null : "cannot find class for " + fileName + " in " + f; f.delete(); if (DEBUG) System.err.println(("looking for ctor " + ctorCount + " and got " + fcls)); if (fcls != null) return makeFunctionConstructor(cls, fcls); } catch (IOException e) { } return makeFunctionConstructor(cls, cls); } }
public static boolean isRemoteProcedure(MethodReference method, IClassHierarchy cha) { return isCapsuleInterface(cha.lookupClass(method.getDeclaringClass())); }