@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); }
/** * @param t type of object to allocate * @return value number of the newly allocated object */ protected int addStatementsForConcreteSimpleType(final TypeReference t) { // assert we haven't allocated this type already. assert !typesAllocated.contains(t); if (DEBUG) { System.err.println(("addStatementsForConcreteType: " + t)); } NewSiteReference ref = NewSiteReference.make(getNewSiteForType(t), t); int alloc = getLocalForType(t); if (t.isArrayType()) { // for now, just allocate an array of size 1 in each dimension. int dim = t.getDimensionality(); int[] extents = new int[dim]; Arrays.fill(extents, 1); SSANewInstruction a = insts.NewInstruction(alloc, ref, extents); addInstruction(t, a, true); } else { SSANewInstruction a = insts.NewInstruction(alloc, ref); addInstruction(t, a, true); addCtorInvokeInstruction(t, alloc); } SSAReturnInstruction r = insts.ReturnInstruction(alloc, false); addInstruction(t, r, false); return alloc; }
/** * @return the IClass that represents the innermost array element type, or null if the element * type is a primitive */ public IClass getInnermostElementClass() { TypeReference elementType = getReference().getInnermostElementType(); if (elementType.isPrimitiveType()) { return null; } return loader.lookupClass(elementType.getName()); }
public static TypeReference getCapsuleMockupClassReference(TypeReference capsuleInterface) { ClassLoaderReference loader = capsuleInterface.getClassLoader(); TypeName interfaceName = capsuleInterface.getName(); String pkg = interfaceName.getPackage().toString(); String name = interfaceName.getClassName().toString() + CAPSULE_MOCKUP_SUFFIX; return TypeReference.findOrCreateClass(loader, pkg, name); }
/* * @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; }
/** * Package-visible constructor; only for use by ArrayClassLoader class. 'loader' must be the * Primordial IClassLoader. * * <p>[WHY? -- array classes are loaded by the element classloader??] */ ArrayClass(TypeReference type, IClassLoader loader, IClassHierarchy cha) { this.type = type; this.loader = loader; this.cha = cha; TypeReference elementType = type.getInnermostElementType(); if (!elementType.isPrimitiveType()) { IClass klass = loader.lookupClass(elementType.getName()); if (klass == null) { Assertions.UNREACHABLE("caller should not attempt to create an array with type " + type); } } else { // assert loader.getReference().equals(ClassLoaderReference.Primordial); } }
@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()); }
@Override public void visitJavaScriptInvoke(JavaScriptInvoke invk) { // check whether this instruction corresponds to a function expression/declaration if (isFunctionConstructorInvoke(invk)) { int defn = invk.getDef(); // the name of the function String fnName = symtab.getStringValue(invk.getUse(1)); IClass fnClass = cha.lookupClass(TypeReference.findOrCreate(JavaScriptTypes.jsLoader, fnName)); if (fnClass == null) { System.err.println( "cannot find " + fnName + " at " + ((AstMethod) method).getSourcePosition()); return; } IMethod fn = fnClass.getMethod(AstMethodReference.fnSelector); FuncVertex callee = factory.makeFuncVertex(fnClass); // look at all uses for (Iterator<SSAInstruction> uses = du.getUses(defn); uses.hasNext(); ) { SSAInstruction use = uses.next(); // check whether this is a local call if (use instanceof JavaScriptInvoke && ((JavaScriptInvoke) use).getFunction() == defn) { JavaScriptInvoke use_invk = (JavaScriptInvoke) use; // yes, so add edges from arguments to parameters... for (int i = 2; i < use_invk.getNumberOfParameters(); ++i) flowgraph.addEdge( factory.makeVarVertex(caller, use_invk.getUse(i)), factory.makeParamVertex(callee, i - 1)); // ...and from return to result flowgraph.addEdge( factory.makeRetVertex(callee), factory.makeVarVertex(caller, use.getDef())); // note: local calls are never qualified, so there is no flow into the receiver vertex } else { // no, it's a more complicated use, so add flows from/to unknown for (int i = 1; i < fn.getNumberOfParameters(); ++i) flowgraph.addEdge(factory.makeUnknownVertex(), factory.makeParamVertex(callee, i)); flowgraph.addEdge(factory.makeRetVertex(callee), factory.makeUnknownVertex()); } } } else { // this is a genuine function call; find out where the function came from SSAInstruction def = du.getDef(invk.getFunction()); // if it's not a local call, add flows from/to unknown if (!(def instanceof JavaScriptInvoke) || !isFunctionConstructorInvoke((JavaScriptInvoke) def)) { for (int i = 1; i < invk.getNumberOfParameters(); ++i) flowgraph.addEdge( factory.makeVarVertex(caller, invk.getUse(i)), factory.makeUnknownVertex()); flowgraph.addEdge( factory.makeUnknownVertex(), factory.makeVarVertex(caller, invk.getDef())); } } }
/** * @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; }
@Override public boolean equals(Object obj) { if (obj instanceof ArrayClass) { ArrayClass other = (ArrayClass) obj; return loader.equals(other.loader) && type.equals(other.type); } else { return false; } }
private boolean allFieldsArePrimitive(IClass c) { if (c.isArrayClass()) { TypeReference t = c.getReference().getArrayElementType(); return t.isPrimitiveType(); } else { if (c.getReference().equals(TypeReference.JavaLangObject)) { return true; } else { for (Iterator<IField> it = c.getDeclaredInstanceFields().iterator(); it.hasNext(); ) { IField f = it.next(); if (f.getReference().getFieldType().isReferenceType()) { return false; } } return allFieldsArePrimitive(c.getSuperclass()); } } }
/* * @see com.ibm.wala.classLoader.IClass#getSuperclass() */ @Override public IClass getSuperclass() { IClass elt = getElementClass(); assert getReference().getArrayElementType().isPrimitiveType() || elt != null; // super is Ljava/lang/Object in two cases: // 1) [Ljava/lang/Object // 2) [? for primitive arrays (null from getElementClass) if (elt == null || elt.getReference() == getClassLoader().getLanguage().getRootType()) { return loader.lookupClass(getClassLoader().getLanguage().getRootType().getName()); } // else it is array of super of element type (yuck) else { TypeReference eltSuperRef = elt.getSuperclass().getReference(); TypeReference superRef = TypeReference.findOrCreateArrayOf(eltSuperRef); return elt.getSuperclass().getClassLoader().lookupClass(superRef.getName()); } }
@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; }
protected void doNewObject( WalkContext context, CAstNode newNode, int result, Object type, int[] arguments) { assert arguments == null; TypeReference typeRef = TypeReference.findOrCreate(JavaScriptTypes.jsLoader, TypeName.string2TypeName("L" + type)); context .cfg() .addInstruction( insts.NewInstruction( result, NewSiteReference.make(context.cfg().getCurrentInstruction(), typeRef))); }
/** * @param reference a type reference for an array type * @return the dimensionality of the array */ public static int getArrayTypeDimensionality(TypeReference reference) { int mask = reference.getDerivedMask(); if ((mask & PrimitiveMask) == PrimitiveMask) { mask >>= ElementBits; } int dims = 0; while ((mask & ArrayMask) == ArrayMask) { mask >>= ElementBits; dims++; } assert dims > 0; return dims; }
protected void addFieldToList( List<FieldImpl> L, Atom name, ImmutableByteArray fieldType, int accessFlags, Collection<Annotation> annotations) { TypeName T = null; if (fieldType.get(fieldType.length() - 1) == ';') { T = TypeName.findOrCreate(fieldType, 0, fieldType.length() - 1); } else { T = TypeName.findOrCreate(fieldType); } TypeReference type = TypeReference.findOrCreate(getClassLoader().getReference(), T); FieldReference fr = FieldReference.findOrCreate(getReference(), name, type); FieldImpl f = new FieldImpl(this, fr, accessFlags, annotations); L.add(f); }
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); }
@Override public int hashCode() { return type.hashCode(); }
public String getQualifiedNameForReflection() { return type.getName().toString(); // XXX is this the right string? }
private static Result getOrigSDG(Config cfg, IProgressMonitor progress) throws IllegalArgumentException, CancelException, PDGFormatException, IOException, WalaException, InvalidClassFileException { progress.beginTask(Messages.getString("Analyzer.Task_Prepare_IR"), -1); // $NON-NLS-1$ com.ibm.wala.ipa.callgraph.impl.Util.setNativeSpec(cfg.nativesXML); progress.subTask(Messages.getString("Analyzer.SubTask_Analysis_Scope")); // $NON-NLS-1$ ClassLoader loader = cfg.getClass().getClassLoader(); AnalysisScope scope = Util.makeAnalysisScope(cfg, loader); // AnalysisScopeReader.makeJavaBinaryAnalysisScope(cfg.scopeFile, cfg.classpath, null); progress.done(); ClassHierarchy cha = ClassHierarchy.make(scope, progress); Iterable<Entrypoint> entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, cfg.mainClass); AnalysisOptions options = new AnalysisOptions(scope, entrypoints); AnalysisCache cache = new AnalysisCache(); progress.subTask( Messages.getString("Analyzer.SubTask_Call_Graph_Builder") + cfg.pointsTo); // $NON-NLS-1$ SSAPropagationCallGraphBuilder builder = SDGFactory.getCallGraphBuilder(cfg.pointsTo, options, cache, cha, scope); /** * Change the wala internal pointer and instancekeyfactory of the callgraph builder to our * adapter. So we can keep track of the created InstanceKeys and PointerKeys. This information * is used later on when creating subobject trees for accessed field variables. */ InstanceAndPointerKeyFactoryAdapter adapter = null; InstanceKeyFactory ikFact = builder.getInstanceKeys(); PointerKeyFactory pkFact = builder.getPointerKeyFactory(); adapter = new InstanceAndPointerKeyFactoryAdapter(ikFact, pkFact); builder.setInstanceKeys(adapter); builder.setPointerKeyFactory(adapter); progress.done(); progress.subTask(Messages.getString("Analyzer.SubTask_Call_Graph")); // $NON-NLS-1$ CallGraph cg = builder.makeCallGraph(options, progress); if (cfg.optimizeCg >= 0) { CallGraphPruning opt = new CallGraphPruning(cg); System.out.println("Call Graph has " + cg.getNumberOfNodes() + " Nodes."); Set<CGNode> sopt = opt.findApplicationNodes(cfg.optimizeCg); cg = new PrunedCallGraph(cg, sopt); System.out.println("Optimized Call Graph has " + cg.getNumberOfNodes() + " Nodes."); } if (Debug.Var.DUMP_CALLGRAPH.isSet()) { Util.dumpCallGraph(cg, cfg.mainClass.replace('/', '.').substring(1), progress); } if (Debug.Var.DUMP_HEAP_GRAPH.isSet()) { PointerAnalysis pta = builder.getPointerAnalysis(); HeapGraph hg = pta.getHeapGraph(); Util.dumpHeapGraph( cfg.mainClass.replace('/', '.').substring(1) + "." + cfg.pointsTo, hg, null); } PointerAnalysis pta = builder.getPointerAnalysis(); progress.done(); DemandRefinementPointsTo demandPts = null; if (cfg.useDemandPts) { throw new UnsupportedOperationException(); // MemoryAccessMap mam = new PABasedMemoryAccessMap(cg, builder.getPointerAnalysis()); // demandPts = new DemandRefinementPointsTo(cg, // new ThisFilteringHeapModel(builder,cha), mam, cha, options, getStateMachineFactory()); } IPointerAnalysis pts = new PointsToWrapper(demandPts, pta); progress.subTask(Messages.getString("Analyzer.SubTask_Search_Main")); // $NON-NLS-1$ IMethod main = edu.kit.joana.deprecated.jsdg.util.Util.searchMethod( entrypoints, "main([Ljava/lang/String;)V"); // $NON-NLS-1$ progress.done(); progress.done(); SDG sdg = SDG.create(main, cg, cache, adapter, pts, cfg, progress); sdg.setAnalysisScope(scope); sdg.setPointerAnalysis(pta); progress.done(); if (Debug.Var.PRINT_FIELD_PTS_INFO.isSet()) { Log.info("search for field allocs called " + PDG.searchFieldAllocs + " times."); } if (Debug.Var.PRINT_UNRESOLVED_CLASSES.isSet()) { for (TypeReference tRef : cg.getClassHierarchy().getUnresolvedClasses()) { Log.warn("Could not resolve: " + Util.typeName(tRef.getName())); } } return new Result(null, sdg, cg, pta, null); }
private boolean isReflectiveType(TypeReference type) { return type.equals(TypeReference.JavaLangReflectConstructor) || type.equals(TypeReference.JavaLangReflectMethod); }
private void run(IProgressMonitor progress) throws CancelException { final Map<PDGNode, PDGNode[]> entry2out = new HashMap<PDGNode, PDGNode[]>(); // add out nodes for each non-primitive parameter for (final PDG pdg : sdg.getAllPDGs()) { // primitive types nodes are null final PDGNode[] formOuts = new PDGNode[pdg.params.length]; for (int i = 0; i < pdg.params.length; i++) { final PDGNode formIn = pdg.params[i]; final TypeReference type = pdg.getParamType(i); if (createOutputParamFor(type)) { final PDGNode formOut = pdg.addOutputFieldChildTo( pdg.entry, formIn.getLabel(), formIn.getBytecodeName(), formIn.getBytecodeIndex(), formIn.getTypeRef()); formOuts[i] = formOut; } } entry2out.put(pdg.entry, formOuts); for (final PDGNode call : pdg.getCalls()) { final PDGNode[] actIns = pdg.getParamIn(call); final PDGNode[] actOuts = new PDGNode[actIns.length]; for (int i = 0; i < actIns.length; i++) { final PDGNode actIn = actIns[i]; final TypeReference type = pdg.getParamType(call, i); if (createOutputParamFor(type)) { final PDGNode actOut = pdg.addOutputFieldChildTo( call, actIn.getLabel(), actIn.getBytecodeName(), actIn.getBytecodeIndex(), actIn.getTypeRef()); actOuts[i] = actOut; } } entry2out.put(call, actOuts); } } // connect form-outs of called procedures with act-outs for (final PDG pdg : sdg.getAllPDGs()) { for (final PDGNode call : pdg.getCalls()) { final PDGNode[] actOuts = entry2out.get(call); assert actOuts != null; for (final PDGEdge out : pdg.outgoingEdgesOf(call)) { if (out.kind == PDGEdge.Kind.CALL_STATIC || out.kind == PDGEdge.Kind.CALL_VIRTUAL) { final PDGNode calleeEntry = out.to; final PDGNode[] formOuts = entry2out.get(calleeEntry); final PDG callee = sdg.getPDGforId(calleeEntry.getPdgId()); assert formOuts != null; assert actOuts.length == formOuts.length; for (int i = 0; i < actOuts.length; i++) { final PDGNode actOut = actOuts[i]; if (actOut != null) { // primitive type (and immutable type) params have no act out callee.addVertex(actOut); final PDGNode formOut = formOuts[i]; if (formOut != null) { callee.addEdge(formOut, actOut, PDGEdge.Kind.PARAMETER_OUT); } } } } } } } // collect reachable points-to elements for reachable fields for each parameter for (final PDG pdg : sdg.getAllPDGs()) { final Map<PDGNode, OrdinalSet<InstanceKey>> node2ptsMod = new HashMap<PDGNode, OrdinalSet<InstanceKey>>(); final Map<PDGNode, OrdinalSet<InstanceKey>> node2ptsRef = new HashMap<PDGNode, OrdinalSet<InstanceKey>>(); final IR ir = pdg.cgNode.getIR(); if (ir == null) { continue; } for (int i = 0; i < pdg.params.length; i++) { if (!pdg.getParamType(i).isPrimitiveType()) { final PDGNode formIn = pdg.params[i]; final int ssaVar = ir.getParameter(i); if (ssaVar >= 0) { final OrdinalSet<InstanceKey> ptsSet = findReachableInstances(pdg.cgNode, ssaVar); node2ptsMod.put(formIn, ptsSet); } } } final PDGNode[] formOuts = entry2out.get(pdg.entry); for (int i = 0; i < formOuts.length; i++) { final PDGNode formOut = formOuts[i]; if (formOut != null) { final PDGNode formIn = pdg.params[i]; final OrdinalSet<InstanceKey> ptsSet = node2ptsMod.get(formIn); node2ptsRef.put(formOut, ptsSet); } } final TypeReference retType = pdg.getMethod().getReturnType(); if (retType != TypeReference.Void && !retType.isPrimitiveType()) { for (final PDGNode retNode : pdg.getReturns()) { final SSAReturnInstruction ret = (SSAReturnInstruction) pdg.getInstruction(retNode); final int ssaVar = ret.getResult(); final OrdinalSet<InstanceKey> ptsSet = findReachableInstances(pdg.cgNode, ssaVar); node2ptsRef.put(retNode, ptsSet); } } for (final PDGNode call : pdg.getCalls()) { final PDGNode[] actIns = pdg.getParamIn(call); final SSAAbstractInvokeInstruction invk = (SSAAbstractInvokeInstruction) pdg.getInstruction(call); for (int i = 0; i < actIns.length; i++) { if (!pdg.getParamType(call, i).isPrimitiveType()) { final PDGNode actIn = actIns[i]; final int ssaVar = invk.getUse(i); if (ssaVar >= 0) { final OrdinalSet<InstanceKey> ptsSet = findReachableInstances(pdg.cgNode, ssaVar); node2ptsRef.put(actIn, ptsSet); } } } final PDGNode actOuts[] = entry2out.get(call); for (int i = 0; i < actIns.length; i++) { final PDGNode actOut = actOuts[i]; if (actOut != null) { final PDGNode actIn = actIns[i]; final OrdinalSet<InstanceKey> ptsSet = node2ptsRef.get(actIn); node2ptsMod.put(actOut, ptsSet); } } final TypeReference callRetType = invk.getDeclaredTarget().getReturnType(); if (callRetType != TypeReference.Void && !callRetType.isPrimitiveType()) { final int ssaVar = invk.getReturnValue(0); final OrdinalSet<InstanceKey> ptsSet = findReachableInstances(pdg.cgNode, ssaVar); final PDGNode retNode = pdg.getReturnOut(call); node2ptsMod.put(retNode, ptsSet); } } // create mod/ref sets for get & set instructions for (final PDGField read : pdg.getFieldReads()) { if (!read.field.isStatic()) { if (read.field.isArray()) { final SSAArrayLoadInstruction ali = (SSAArrayLoadInstruction) pdg.getInstruction(read.node); final int ssaVarBase = ali.getArrayRef(); if (ssaVarBase >= 0) { final OrdinalSet<InstanceKey> ptsSet = pointsToArrayField(pdg.cgNode, ssaVarBase); node2ptsRef.put(read.accfield, ptsSet); } } else { final SSAGetInstruction get = (SSAGetInstruction) pdg.getInstruction(read.node); final int ssaVarBase = get.getRef(); if (ssaVarBase >= 0) { final IField field = sdg.getClassHierarchy().resolveField(get.getDeclaredField()); final OrdinalSet<InstanceKey> ptsSet = pointsToObjectField(pdg.cgNode, ssaVarBase, field); node2ptsRef.put(read.accfield, ptsSet); } } // final SSAInstruction get = pdg.getInstruction(read.node); // final int ssaVar = get.getDef(); // if (ssaVar >= 0) { // final OrdinalSet<InstanceKey> ptsSet = findReachableInstances(pdg.cgNode, ssaVar); // node2ptsRef.put(read.accfield, ptsSet); // } } } for (final PDGField write : pdg.getFieldWrites()) { if (!write.field.isStatic()) { if (write.field.isArray()) { final SSAArrayStoreInstruction asi = (SSAArrayStoreInstruction) pdg.getInstruction(write.node); final int ssaVarBase = asi.getArrayRef(); if (ssaVarBase >= 0) { final OrdinalSet<InstanceKey> ptsSet = pointsToArrayField(pdg.cgNode, ssaVarBase); node2ptsMod.put(write.accfield, ptsSet); } } else { final SSAPutInstruction put = (SSAPutInstruction) pdg.getInstruction(write.node); final int ssaVarBase = put.getRef(); if (ssaVarBase >= 0) { final IField field = sdg.getClassHierarchy().resolveField(put.getDeclaredField()); final OrdinalSet<InstanceKey> ptsSet = pointsToObjectField(pdg.cgNode, ssaVarBase, field); node2ptsMod.put(write.accfield, ptsSet); } } } } // add data flow for each pdg FlatHeapParamsDataFlow.compute( pdg, node2ptsMod, node2ptsRef, (sdg.cfg.accessPath ? PDGEdge.Kind.DATA_ALIAS : PDGEdge.Kind.DATA_HEAP), progress); } }
public static boolean isKnownSafeTypeForTransfer(TypeReference typeRef) { // TODO: Add String and primitive box types (e.g. Integer). return typeRef.isPrimitiveType(); }
/** * Flexible class to create {@link InstanceKey}s depending on various policies ranging from * class-based (i.e. 0-CFA) to allocation-site-based (0-1-CFA variants). */ public class ZeroXInstanceKeys implements InstanceKeyFactory { private static final TypeName JavaLangStringBufferName = TypeName.string2TypeName("Ljava/lang/StringBuffer"); public static final TypeReference JavaLangStringBuffer = TypeReference.findOrCreate(ClassLoaderReference.Primordial, JavaLangStringBufferName); private static final TypeName JavaLangStringBuilderName = TypeName.string2TypeName("Ljava/lang/StringBuilder"); public static final TypeReference JavaLangStringBuilder = TypeReference.findOrCreate(ClassLoaderReference.Primordial, JavaLangStringBuilderName); private static final TypeName JavaLangAbstractStringBuilderName = TypeName.string2TypeName("Ljava/lang/AbstractStringBuilder"); public static final TypeReference JavaLangAbstractStringBuilder = TypeReference.findOrCreate( ClassLoaderReference.Primordial, JavaLangAbstractStringBuilderName); /** The NONE policy is not allocation-site based */ public static final int NONE = 0; /** * An ALLOCATIONS - based policy distinguishes instances by allocation site. Otherwise, the policy * distinguishes instances by type. */ public static final int ALLOCATIONS = 1; /** * A policy variant where String and StringBuffers are NOT disambiguated according to allocation * site. */ public static final int SMUSH_STRINGS = 2; /** * A policy variant where {@link Throwable} instances are NOT disambiguated according to * allocation site. */ public static final int SMUSH_THROWABLES = 4; /** * A policy variant where if a type T has only primitive instance fields, then instances of type T * are NOT disambiguated by allocation site. */ public static final int SMUSH_PRIMITIVE_HOLDERS = 8; /** * This variant counts the N, number of allocation sites of a particular type T in each method. If * N > SMUSH_LIMIT, then these N allocation sites are NOT distinguished ... instead there is a * single abstract allocation site for <N,T> * * <p>Probably the best choice in many cases. */ public static final int SMUSH_MANY = 16; /** Should we use constant-specific keys? */ public static final int CONSTANT_SPECIFIC = 32; /** When using smushing, how many sites in a node will be kept distinct before smushing? */ private final int SMUSH_LIMIT = 25; /** The policy choice for instance disambiguation */ private final int policy; /** A delegate object to create class-based abstract instances */ private final ClassBasedInstanceKeys classBased; /** A delegate object to create allocation site-based abstract instances */ private final AllocationSiteInNodeFactory siteBased; /** A delegate object to create "abstract allocation site" - based abstract instances */ private final SmushedAllocationSiteInstanceKeys smushed; /** The governing class hierarchy */ private final IClassHierarchy cha; /** An object which interprets nodes in context. */ private final RTAContextInterpreter contextInterpreter; /** a Map from CGNode->Set<IClass> that should be smushed. */ protected final Map<CGNode, Set<IClass>> smushMap = HashMapFactory.make(); public ZeroXInstanceKeys( AnalysisOptions options, IClassHierarchy cha, RTAContextInterpreter contextInterpreter, int policy) { if (options == null) { throw new IllegalArgumentException("null options"); } this.policy = policy; if (disambiguateConstants()) { // this is an ugly hack. TODO: clean it all up. options.setUseConstantSpecificKeys(true); } classBased = new ClassBasedInstanceKeys(options, cha); siteBased = new AllocationSiteInNodeFactory(options, cha); smushed = new SmushedAllocationSiteInstanceKeys(options, cha); this.cha = cha; this.contextInterpreter = contextInterpreter; } /** @return true iff the policy smushes some allocation sites */ private boolean smushMany() { return (policy & SMUSH_MANY) > 0; } private boolean allocationPolicy() { return (policy & ALLOCATIONS) > 0; } private boolean smushStrings() { return (policy & SMUSH_STRINGS) > 0; } public boolean smushThrowables() { return (policy & SMUSH_THROWABLES) > 0; } private boolean smushPrimHolders() { return (policy & SMUSH_PRIMITIVE_HOLDERS) > 0; } public boolean disambiguateConstants() { return (policy & CONSTANT_SPECIFIC) > 0; } 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); } } /** * 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); } /** @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; } public InstanceKey getInstanceKeyForMultiNewArray( CGNode node, NewSiteReference allocation, int dim) { if (allocationPolicy()) { return siteBased.getInstanceKeyForMultiNewArray(node, allocation, dim); } else { return classBased.getInstanceKeyForMultiNewArray(node, allocation, dim); } } public <T> InstanceKey getInstanceKeyForConstant(TypeReference type, T S) { if (type == null) { throw new IllegalArgumentException("null type"); } if (disambiguateConstants() || isReflectiveType(type)) { return new ConstantKey<T>(S, getClassHierarchy().lookupClass(type)); } else { return classBased.getInstanceKeyForConstant(type, S); } } private boolean isReflectiveType(TypeReference type) { return type.equals(TypeReference.JavaLangReflectConstructor) || type.equals(TypeReference.JavaLangReflectMethod); } /* * @see com.ibm.wala.ipa.callgraph.propagation.InstanceKeyFactory#getInstanceKeyForPEI(com.ibm.wala.ipa.callgraph.CGNode, * com.ibm.wala.classLoader.ProgramCounter, com.ibm.wala.types.TypeReference) */ public InstanceKey getInstanceKeyForPEI(CGNode node, ProgramCounter pei, TypeReference type) { return classBased.getInstanceKeyForPEI(node, pei, type); } public InstanceKey getInstanceKeyForClassObject(TypeReference type) { return classBased.getInstanceKeyForClassObject(type); } /** A class is "interesting" iff we distinguish instances of the class */ public boolean isInteresting(IClass C) { if (!allocationPolicy()) { return false; } else { if (smushStrings() && isStringish(C)) { return false; } else if (smushThrowables() && (isThrowable(C) || isStackTraceElement(C))) { return false; } else if (smushPrimHolders() && allFieldsArePrimitive(C)) { return false; } return true; } } public static boolean isStringish(IClass C) { if (C == null) { throw new IllegalArgumentException("C is null"); } return C.getReference().equals(TypeReference.JavaLangString) || C.getReference().equals(JavaLangStringBuffer) || C.getReference().equals(JavaLangStringBuilder) || C.getReference().equals(JavaLangAbstractStringBuilder); } public static boolean isThrowable(IClass c) { if (c == null) { throw new IllegalArgumentException("null c"); } return c.getClassHierarchy() .isSubclassOf(c, c.getClassHierarchy().lookupClass(TypeReference.JavaLangThrowable)); } public boolean isStackTraceElement(IClass c) { if (c == null) { throw new IllegalArgumentException("C is null"); } return c.getReference().equals(TypeReference.JavaLangStackTraceElement); } private boolean allFieldsArePrimitive(IClass c) { if (c.isArrayClass()) { TypeReference t = c.getReference().getArrayElementType(); return t.isPrimitiveType(); } else { if (c.getReference().equals(TypeReference.JavaLangObject)) { return true; } else { for (Iterator<IField> it = c.getDeclaredInstanceFields().iterator(); it.hasNext(); ) { IField f = it.next(); if (f.getReference().getFieldType().isReferenceType()) { return false; } } return allFieldsArePrimitive(c.getSuperclass()); } } } protected IClassHierarchy getClassHierarchy() { return cha; } public ClassBasedInstanceKeys getClassBasedInstanceKeys() { return classBased; } }
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); } }
/** * @param m * @return true iff we can treat m as a no-op method */ protected boolean canIgnore(MemberReference m) { TypeReference T = m.getDeclaringClass(); TypeName n = T.getName(); Atom p = n.getPackage(); return (ignoredPackages.contains(p)); }
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; }
private boolean createOutputParamFor(final TypeReference type) { return !type.isPrimitiveType() && !sdg.isImmutableNoOutParam(type); }