@Override public String toString() { StringBuilder s = new StringBuilder(); String n = String.format("%n"); s.append("Equivalent methods:" + n); for (Method bzm : manifest.getBaseMethods()) { s.append(" " + bzm.getName() + " -> { "); for (Method zm : ELM.get(bzm)) s.append(zm.getReturnType() + ":" + zm.getName() + " "); // TODO fix this info s.append("}" + n); } s.append("Equivalent types:" + n); for (JavaClass bzt : manifest.getBaseTypes()) { s.append(" " + bzt.getClassName() + " -> { "); for (JavaClass zt : ET.get(bzt)) s.append(zt.getClassName() + " "); s.append("}" + n); } s.append("Method costs:" + n); for (Method zm : CLM.keySet()) s.append(" " + zm.getName() + " -> " + CLM.get(zm).getName() + n); s.append("Transformation costs:" + n); for (Method zs : CLS.keySet()) s.append(" " + zs.getName() + " -> " + CLS.get(zs).getName() + n); return s.toString(); }
@Override public void visit(JavaClass obj) { compute(); ConstantPool cp = obj.getConstantPool(); Constant[] constants = cp.getConstantPool(); checkConstant: for (int i = 0; i < constants.length; i++) { Constant co = constants[i]; if (co instanceof ConstantDouble || co instanceof ConstantLong) i++; if (co instanceof ConstantClass) { String ref = getClassName(obj, i); if ((ref.startsWith("java") || ref.startsWith("org.w3c.dom")) && !defined.contains(ref)) bugReporter.reportBug( new BugInstance(this, "VR_UNRESOLVABLE_REFERENCE", NORMAL_PRIORITY) .addClass(obj) .addString(ref)); } else if (co instanceof ConstantFieldref) { // do nothing until we handle static fields defined in interfaces } else if (co instanceof ConstantCP) { ConstantCP co2 = (ConstantCP) co; String className = getClassName(obj, co2.getClassIndex()); // System.out.println("checking " + ref); if (className.equals(obj.getClassName()) || !defined.contains(className)) { // System.out.println("Skipping check of " + ref); continue checkConstant; } ConstantNameAndType nt = (ConstantNameAndType) cp.getConstant(co2.getNameAndTypeIndex()); String name = ((ConstantUtf8) obj.getConstantPool().getConstant(nt.getNameIndex(), CONSTANT_Utf8)) .getBytes(); String signature = ((ConstantUtf8) obj.getConstantPool().getConstant(nt.getSignatureIndex(), CONSTANT_Utf8)) .getBytes(); try { JavaClass target = Repository.lookupClass(className); if (!find(target, name, signature)) bugReporter.reportBug( new BugInstance(this, "VR_UNRESOLVABLE_REFERENCE", NORMAL_PRIORITY) .addClass(obj) .addString(getMemberName(target.getClassName(), name, signature))); } catch (ClassNotFoundException e) { bugReporter.reportMissingClass(e); } } } }
@Override public void sawOpcode(int seen) { if (seen == PUTFIELD) { XField xField = getXFieldOperand(); if (xField != null && xField.getClassDescriptor().equals(getClassDescriptor())) { Item first = stack.getStackItem(0); boolean isPutOfDefaultValue = first.isNull(); // huh?? || first.isInitialParameter(); if (!isPutOfDefaultValue && first.getConstant() != null) { Object constant = first.getConstant(); if (constant instanceof Number && ((Number) constant).intValue() == 0 || constant.equals(Boolean.FALSE)) isPutOfDefaultValue = true; } if (isPutOfDefaultValue) { if (getMethodName().equals("<init>")) transientFieldsSetToDefaultValueInConstructor.add(xField); } else { String nameOfField = getNameConstantOperand(); if (transientFieldsUpdates.containsKey(xField)) { if (getMethodName().equals("<init>")) transientFieldsSetInConstructor.add(xField); else transientFieldsUpdates.put(xField, transientFieldsUpdates.get(xField) + 1); } else if (fieldsThatMightBeAProblem.containsKey(nameOfField)) { try { JavaClass classStored = first.getJavaClass(); if (classStored == null) { return; } double isSerializable = DeepSubtypeAnalysis.isDeepSerializable(classStored); if (isSerializable <= 0.2) { XField f = fieldsThatMightBeAProblem.get(nameOfField); String sig = f.getSignature(); // System.out.println("Field signature: " + sig); // System.out.println("Class stored: " + // classStored.getClassName()); String genSig = "L" + classStored.getClassName().replace('.', '/') + ";"; if (!sig.equals(genSig)) { double bias = 0.0; if (!getMethodName().equals("<init>")) bias = 1.0; int priority = computePriority(isSerializable, bias); fieldWarningList.add( new BugInstance(this, "SE_BAD_FIELD_STORE", priority) .addClass(getThisClass().getClassName()) .addField(f) .addType(genSig) .describe("TYPE_FOUND") .addSourceLine(this)); } } } catch (Exception e) { // ignore it } } } } } }
@Override public ArtifactBuilder buildArtifacts( BaseArtifactType primaryArtifact, ArtifactContent artifactContent) throws IOException { super.buildArtifacts(primaryArtifact, artifactContent); ClassParser parser = new ClassParser(getContentStream(), primaryArtifact.getName()); JavaClass javaClass = parser.parse(); if (javaClass.isInterface()) { ((ExtendedDocument) primaryArtifact).setExtendedType(JavaModel.TYPE_JAVA_INTERFACE); } else if (javaClass.isClass()) { ((ExtendedDocument) primaryArtifact).setExtendedType(JavaModel.TYPE_JAVA_CLASS); } else if (javaClass.isEnum()) { ((ExtendedDocument) primaryArtifact).setExtendedType(JavaModel.TYPE_JAVA_ENUM); } String packageName = javaClass.getPackageName(); String className = javaClass.getClassName(); primaryArtifact.setName(className); String shortName = className; if (className.lastIndexOf('.') > 0) { shortName = className.substring(className.lastIndexOf('.') + 1); } SrampModelUtils.setCustomProperty(primaryArtifact, JavaModel.PROP_PACKAGE_NAME, packageName); SrampModelUtils.setCustomProperty(primaryArtifact, JavaModel.PROP_CLASS_NAME, shortName); return this; }
/** * Write contents of the given JavaClass into HTML files. * * @param java_class The class to write * @param dir The directory to put the files in */ public Class2HTML(JavaClass java_class, String dir) throws IOException { Method[] methods = java_class.getMethods(); this.java_class = java_class; this.dir = dir; class_name = java_class.getClassName(); // Remember full name constant_pool = java_class.getConstantPool(); // Get package name by tacking off everything after the last `.' int index = class_name.lastIndexOf('.'); if (index > -1) class_package = class_name.substring(0, index); else class_package = ""; // default package ConstantHTML constant_html = new ConstantHTML(dir, class_name, class_package, methods, constant_pool); /* Attributes can't be written in one step, so we just open a file * which will be written consequently. */ AttributeHTML attribute_html = new AttributeHTML(dir, class_name, constant_pool, constant_html); // MethodHTML method_html = new MethodHTML(dir, class_name, methods, java_class.getFields(), // constant_html, attribute_html); // Write main file (with frames, yuk) writeMainHTML(attribute_html); new CodeHTML(dir, class_name, methods, constant_pool, constant_html); attribute_html.close(); }
public static void main(String[] argv) throws Exception { JavaClass clazz = null; if ((clazz = Repository.lookupClass(argv[0])) == null) { clazz = new ClassParser(argv[0]).parse(); // May throw IOException } ClassGen cg = new ClassGen(clazz); Method[] methods = clazz.getMethods(); for (int i = 0; i < methods.length; i++) { MethodGen mg = new MethodGen(methods[i], cg.getClassName(), cg.getConstantPool()); cg.replaceMethod(methods[i], mg.getMethod()); } Field[] fields = clazz.getFields(); for (int i = 0; i < fields.length; i++) { FieldGen fg = new FieldGen(fields[i], cg.getConstantPool()); cg.replaceField(fields[i], fg.getField()); } cg.getJavaClass().dump(clazz.getClassName() + ".clazz"); }
/** * Dumps the contents of the specified class to the specified directory. The file is named * dump_dir/[class].bcel. It contains a synopsis of the fields and methods followed by the jvm * code for each method. * * @param jc javaclass to dump * @param dump_dir directory in which to write the file */ public static void dump(JavaClass jc, File dump_dir) { try { dump_dir.mkdir(); File path = new File(dump_dir, jc.getClassName() + ".bcel"); PrintStream p = new PrintStream(path); // Print the class, super class and interfaces p.printf("class %s extends %s\n", jc.getClassName(), jc.getSuperclassName()); String[] inames = jc.getInterfaceNames(); if ((inames != null) && (inames.length > 0)) { p.printf(" "); for (String iname : inames) p.printf("implements %s ", iname); p.printf("\n"); } // Print each field p.printf("\nFields\n"); for (Field f : jc.getFields()) p.printf(" %s\n", f); // Print the signature of each method p.printf("\nMethods\n"); for (Method m : jc.getMethods()) p.printf(" %s\n", m); // If this is not an interface, print the code for each method if (!jc.isInterface()) { for (Method m : jc.getMethods()) { p.printf("\nMethod %s\n", m); Code code = m.getCode(); if (code != null) p.printf(" %s\n", code.toString().replace("\n", "\n ")); } } // Print the details of the constant pool. p.printf("Constant Pool:\n"); ConstantPool cp = jc.getConstantPool(); Constant[] constants = cp.getConstantPool(); for (int ii = 0; ii < constants.length; ii++) { p.printf(" %d %s\n", ii, constants[ii]); } p.close(); } catch (Exception e) { throw new Error("Unexpected error dumping javaclass", e); } }
/** * Construct a MethodDescriptor from JavaClass and method. * * @param jclass a JavaClass * @param method a Method belonging to the JavaClass * @return a MethodDescriptor identifying the method */ public static MethodDescriptor getMethodDescriptor(JavaClass jclass, Method method) { return DescriptorFactory.instance() .getMethodDescriptor( jclass.getClassName().replace('.', '/'), method.getName(), method.getSignature(), method.isStatic()); }
private boolean find(JavaClass target, String name, String signature) throws ClassNotFoundException { if (target == null) return false; String ref = getMemberName(target.getClassName(), name, signature); if (defined.contains(ref)) return true; if (find(target.getSuperClass(), name, signature)) return true; for (JavaClass i : target.getInterfaces()) if (find(i, name, signature)) return true; return false; }
/** * Constructor is only used by following two factory methods: getTemplate for the dispatch of the * creation with newClassInfo * * @param clazz * @param ai */ private JopClassInfo(JavaClass clazz, OldAppInfo ai) { super(clazz, ai); methodsAddress = 0; cpoolAddress = 0; instSize = 0; instGCinfo = 0; cpoolUsed = new LinkedList<Integer>(); // the template class info is created with a null pointer if (clazz != null) { if (clazz.getClassName().equals(JOPizer.stringClass)) { StringInfo.cli = this; } if (clazz.getClassName().equals(JOPizer.objectClass)) { nrObjMethods = clazz.getMethods().length; } } }
public void visitJavaClass(JavaClass clazz) { super.visitJavaClass(clazz); JopClassInfo cli = (JopClassInfo) this.cli; cpool = clazz.getConstantPool(); if (clazz.isInterface()) { cli.interfaceID = ++cli.interfaceCnt; cli.interfaceList.add(cli.interfaceID - 1, clazz.getClassName()); } }
public void addAllDefinitions(JavaClass obj) { String className2 = obj.getClassName(); defined.add(className2); for (Method m : obj.getMethods()) if (!m.isPrivate()) { String name = getMemberName(obj, className2, m.getNameIndex(), m.getSignatureIndex()); defined.add(name); } for (Field f : obj.getFields()) if (!f.isPrivate()) { String name = getMemberName(obj, className2, f.getNameIndex(), f.getSignatureIndex()); defined.add(name); } }
public void visitClassContext(ClassContext classContext) { JavaClass javaClass = classContext.getJavaClass(); Method[] methodList = javaClass.getMethods(); for (Method method : methodList) { if (method.getCode() == null) continue; try { analyzeMethod(classContext, method); } catch (MethodUnprofitableException e) { assert true; // move along; nothing to see } catch (CFGBuilderException e) { String msg = "Detector " + this.getClass().getName() + " caught exception while analyzing " + javaClass.getClassName() + "." + method.getName() + " : " + method.getSignature(); bugReporter.logError(msg, e); } catch (DataflowAnalysisException e) { String msg = "Detector " + this.getClass().getName() + " caught exception while analyzing " + javaClass.getClassName() + "." + method.getName() + " : " + method.getSignature(); bugReporter.logError(msg, e); } } }
/** * looks to see if this class (or some class in its hierarchy (besides Object) has implemented the * specified method. * * @param cls the class to look in * @param methodName the method name to look for * @param methodSig the method signature to look for * @return when toString is found * @throws ClassNotFoundException if a super class can't be found */ private static boolean hasMethodInHierarchy(JavaClass cls, String methodName, String methodSig) throws ClassNotFoundException { MethodInfo mi = null; do { String clsName = cls.getClassName(); if (Values.DOTTED_JAVA_LANG_OBJECT.equals(clsName)) { return false; } mi = Statistics.getStatistics() .getMethodStatistics(clsName.replace('.', '/'), methodName, methodSig); cls = cls.getSuperClass(); } while (mi.getNumBytes() == 0); return true; }
/** * Get the ClassContext for a class. * * @param javaClass the class * @return the ClassContext for that class */ public ClassContext getClassContext(JavaClass javaClass) { // This is a bit silly since we're doing an unnecessary // ClassDescriptor->JavaClass lookup. // However, we can be assured that it will succeed. ClassDescriptor classDescriptor = DescriptorFactory.instance() .getClassDescriptor(ClassName.toSlashedClassName(javaClass.getClassName())); try { return Global.getAnalysisCache().getClassAnalysis(ClassContext.class, classDescriptor); } catch (CheckedAnalysisException e) { IllegalStateException ise = new IllegalStateException("Could not get ClassContext for JavaClass"); ise.initCause(e); throw ise; } }
public static @CheckForNull JavaClassAndMethod findMethod( JavaClass javaClass, String methodName, String methodSig, JavaClassAndMethodChooser chooser) { if (DEBUG_METHOD_LOOKUP) { System.out.println("Check " + javaClass.getClassName()); } Method[] methodList = javaClass.getMethods(); for (Method method : methodList) if (method.getName().equals(methodName) && method.getSignature().equals(methodSig)) { JavaClassAndMethod m = new JavaClassAndMethod(javaClass, method); if (chooser.choose(m)) { if (DEBUG_METHOD_LOOKUP) { System.out.println("\t==> FOUND: " + method); } return m; } } if (DEBUG_METHOD_LOOKUP) { System.out.println("\t==> NOT FOUND"); } return null; }
/** * Find a method in given class. * * @param javaClass the class * @param methodName the name of the method * @param methodSig the signature of the method * @return the JavaClassAndMethod, or null if no such method exists in the class */ @Deprecated public static @CheckForNull JavaClassAndMethod findConcreteMethod( JavaClass javaClass, String methodName, String methodSig) { if (DEBUG_METHOD_LOOKUP) { System.out.println("Check " + javaClass.getClassName()); } Method[] methodList = javaClass.getMethods(); for (Method method : methodList) if (method.getName().equals(methodName) && method.getSignature().equals(methodSig) && accessFlagsAreConcrete(method.getAccessFlags())) { JavaClassAndMethod m = new JavaClassAndMethod(javaClass, method); return m; } if (DEBUG_METHOD_LOOKUP) { System.out.println("\t==> NOT FOUND"); } return null; }
@Override public void visit(Code obj) { if (!directChildOfTestCase && (getMethodName().equals("setUp") || getMethodName().equals("tearDown")) && !getMethod().isPrivate() && getMethodSig().equals("()V")) { sawSuperCall = false; super.visit(obj); if (sawSuperCall) { return; } JavaClass we = Lookup.findSuperImplementor(getThisClass(), getMethodName(), "()V", bugReporter); if (we != null && !we.getClassName().equals("junit.framework.TestCase")) { // OK, got a bug int offset = 0; if (getMethodName().equals("tearDown")) { offset = obj.getCode().length - 1; } Method superMethod = Lookup.findImplementation(we, getMethodName(), "()V"); Code superCode = superMethod.getCode(); if (superCode != null && superCode.getCode().length > 3) { bugReporter.reportBug( new BugInstance( this, getMethodName().equals("setUp") ? "IJU_SETUP_NO_SUPER" : "IJU_TEARDOWN_NO_SUPER", NORMAL_PRIORITY) .addClassAndMethod(this) .addMethod(we, superMethod) .describe(MethodAnnotation.METHOD_OVERRIDDEN) .addSourceLine(this, offset)); } } } }
public void removeClass(JavaClass clazz) { ClassInfo cls = AppInfo.getSingleton().getClassInfo(clazz.getClassName()); if (cls != null) { AppInfo.getSingleton().removeClass(cls, true, true); } }
/** * Pass 3b implements the data flow analysis as described in the Java Virtual Machine * Specification, Second Edition. Later versions will use LocalVariablesInfo objects to verify if * the verifier-inferred types and the class file's debug information (LocalVariables attributes) * match [TODO]. * * @see org.apache.bcel.verifier.statics.LocalVariablesInfo * @see org.apache.bcel.verifier.statics.Pass2Verifier#getLocalVariablesInfo(int) */ @Override public VerificationResult do_verify() { if (!myOwner.doPass3a(method_no).equals(VerificationResult.VR_OK)) { return VerificationResult.VR_NOTYET; } // Pass 3a ran before, so it's safe to assume the JavaClass object is // in the BCEL repository. JavaClass jc; try { jc = Repository.lookupClass(myOwner.getClassName()); } catch (ClassNotFoundException e) { // FIXME: maybe not the best way to handle this throw new AssertionViolatedException("Missing class: " + e, e); } ConstantPoolGen constantPoolGen = new ConstantPoolGen(jc.getConstantPool()); // Init Visitors InstConstraintVisitor icv = new InstConstraintVisitor(); icv.setConstantPoolGen(constantPoolGen); ExecutionVisitor ev = new ExecutionVisitor(); ev.setConstantPoolGen(constantPoolGen); Method[] methods = jc.getMethods(); // Method no "method_no" exists, we ran Pass3a before on it! try { MethodGen mg = new MethodGen(methods[method_no], myOwner.getClassName(), constantPoolGen); icv.setMethodGen(mg); ////////////// DFA BEGINS HERE //////////////// if (!(mg.isAbstract() || mg.isNative())) { // IF mg HAS CODE (See pass 2) ControlFlowGraph cfg = new ControlFlowGraph(mg); // Build the initial frame situation for this method. Frame f = new Frame(mg.getMaxLocals(), mg.getMaxStack()); if (!mg.isStatic()) { if (mg.getName().equals(Constants.CONSTRUCTOR_NAME)) { Frame._this = new UninitializedObjectType(ObjectType.getInstance(jc.getClassName())); f.getLocals().set(0, Frame._this); } else { Frame._this = null; f.getLocals().set(0, ObjectType.getInstance(jc.getClassName())); } } Type[] argtypes = mg.getArgumentTypes(); int twoslotoffset = 0; for (int j = 0; j < argtypes.length; j++) { if (argtypes[j] == Type.SHORT || argtypes[j] == Type.BYTE || argtypes[j] == Type.CHAR || argtypes[j] == Type.BOOLEAN) { argtypes[j] = Type.INT; } f.getLocals().set(twoslotoffset + j + (mg.isStatic() ? 0 : 1), argtypes[j]); if (argtypes[j].getSize() == 2) { twoslotoffset++; f.getLocals().set(twoslotoffset + j + (mg.isStatic() ? 0 : 1), Type.UNKNOWN); } } circulationPump(mg, cfg, cfg.contextOf(mg.getInstructionList().getStart()), f, icv, ev); } } catch (VerifierConstraintViolatedException ce) { ce.extendMessage("Constraint violated in method '" + methods[method_no] + "':\n", ""); return new VerificationResult(VerificationResult.VERIFIED_REJECTED, ce.getMessage()); } catch (RuntimeException re) { // These are internal errors StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); re.printStackTrace(pw); throw new AssertionViolatedException( "Some RuntimeException occured while verify()ing class '" + jc.getClassName() + "', method '" + methods[method_no] + "'. Original RuntimeException's stack trace:\n---\n" + sw + "---\n", re); } return VerificationResult.VR_OK; }
/** * Adds all the constants found in the given class into the given ConstantSet, and returns it. * * @see #getConstants(String) */ public static ConstantSet getConstants(String classname, ConstantSet result) { ClassParser cp; JavaClass jc; try { String classfileBase = classname.replace('.', '/'); InputStream is = ClassPath.SYSTEM_CLASS_PATH.getInputStream(classfileBase, ".class"); cp = new ClassParser(is, classname); jc = cp.parse(); } catch (java.io.IOException e) { throw new Error("IOException while reading '" + classname + "': " + e.getMessage()); } result.classname = jc.getClassName(); // Get all of the constants from the pool ConstantPool constant_pool = jc.getConstantPool(); for (Constant c : constant_pool.getConstantPool()) { // System.out.printf ("*Constant = %s%n", c); if (c == null || c instanceof ConstantClass || c instanceof ConstantFieldref || c instanceof ConstantInterfaceMethodref || c instanceof ConstantMethodref || c instanceof ConstantNameAndType || c instanceof ConstantUtf8) { continue; } if (c instanceof ConstantString) { result.strings.add((String) ((ConstantString) c).getConstantValue(constant_pool)); } else if (c instanceof ConstantDouble) { result.doubles.add((Double) ((ConstantDouble) c).getConstantValue(constant_pool)); } else if (c instanceof ConstantFloat) { result.floats.add((Float) ((ConstantFloat) c).getConstantValue(constant_pool)); } else if (c instanceof ConstantInteger) { result.ints.add((Integer) ((ConstantInteger) c).getConstantValue(constant_pool)); } else if (c instanceof ConstantLong) { result.longs.add((Long) ((ConstantLong) c).getConstantValue(constant_pool)); } else { throw new RuntimeException("Unrecognized constant of type " + c.getClass() + ": " + c); } } ClassGen gen = new ClassGen(jc); ConstantPoolGen pool = gen.getConstantPool(); // Process the code in each method looking for literals for (Method m : jc.getMethods()) { MethodGen mg = new MethodGen(m, jc.getClassName(), pool); InstructionList il = mg.getInstructionList(); if (il == null) { // System.out.println("No instructions for " + mg); } else { for (Instruction inst : il.getInstructions()) { switch (inst.getOpcode()) { // Compare two objects, no literals case Constants.IF_ACMPEQ: case Constants.IF_ACMPNE: break; // These instructions compare the integer on the top of the stack // to zero. There are no literals here (except 0) case Constants.IFEQ: case Constants.IFNE: case Constants.IFLT: case Constants.IFGE: case Constants.IFGT: case Constants.IFLE: { break; } // Instanceof pushes either 0 or 1 on the stack depending on whether // the object on top of stack is of the specified type. // If were interested in class literals, this would be interesting case Constants.INSTANCEOF: break; // Duplicates the item on the top of stack. No literal. case Constants.DUP: { break; } // Duplicates the item on the top of the stack and inserts it 2 // values down in the stack. No literals case Constants.DUP_X1: { break; } // Duplicates either the top 2 category 1 values or a single // category 2 value and inserts it 2 or 3 values down on the // stack. case Constants.DUP2_X1: { break; } // Duplicate either one category 2 value or two category 1 values. case Constants.DUP2: { break; } // Dup the category 1 value on the top of the stack and insert it either // two or three values down on the stack. case Constants.DUP_X2: { break; } case Constants.DUP2_X2: { break; } // Pop instructions discard the top of the stack. case Constants.POP: { break; } // Pops either the top 2 category 1 values or a single category 2 value // from the top of the stack. case Constants.POP2: { break; } // Swaps the two category 1 types on the top of the stack. case Constants.SWAP: { break; } // Compares two integers on the stack case Constants.IF_ICMPEQ: case Constants.IF_ICMPGE: case Constants.IF_ICMPGT: case Constants.IF_ICMPLE: case Constants.IF_ICMPLT: case Constants.IF_ICMPNE: { break; } // Get the value of a field case Constants.GETFIELD: { break; } // stores the top of stack into a field case Constants.PUTFIELD: { break; } // Pushes the value of a static field on the stack case Constants.GETSTATIC: { break; } // Pops a value off of the stack into a static field case Constants.PUTSTATIC: { break; } // pushes a local onto the stack case Constants.DLOAD: case Constants.DLOAD_0: case Constants.DLOAD_1: case Constants.DLOAD_2: case Constants.DLOAD_3: case Constants.FLOAD: case Constants.FLOAD_0: case Constants.FLOAD_1: case Constants.FLOAD_2: case Constants.FLOAD_3: case Constants.ILOAD: case Constants.ILOAD_0: case Constants.ILOAD_1: case Constants.ILOAD_2: case Constants.ILOAD_3: case Constants.LLOAD: case Constants.LLOAD_0: case Constants.LLOAD_1: case Constants.LLOAD_2: case Constants.LLOAD_3: { break; } // Pops a value off of the stack into a local case Constants.DSTORE: case Constants.DSTORE_0: case Constants.DSTORE_1: case Constants.DSTORE_2: case Constants.DSTORE_3: case Constants.FSTORE: case Constants.FSTORE_0: case Constants.FSTORE_1: case Constants.FSTORE_2: case Constants.FSTORE_3: case Constants.ISTORE: case Constants.ISTORE_0: case Constants.ISTORE_1: case Constants.ISTORE_2: case Constants.ISTORE_3: case Constants.LSTORE: case Constants.LSTORE_0: case Constants.LSTORE_1: case Constants.LSTORE_2: case Constants.LSTORE_3: { break; } // Push a value from the runtime constant pool. We'll get these // values when processing the constant pool itself case Constants.LDC: case Constants.LDC_W: case Constants.LDC2_W: { break; } // Push the length of an array on the stack case Constants.ARRAYLENGTH: { break; } // Push small constants (-1..5) on the stack. These literals are // too common to bother mentioning case Constants.DCONST_0: case Constants.DCONST_1: case Constants.FCONST_0: case Constants.FCONST_1: case Constants.FCONST_2: case Constants.ICONST_0: case Constants.ICONST_1: case Constants.ICONST_2: case Constants.ICONST_3: case Constants.ICONST_4: case Constants.ICONST_5: case Constants.ICONST_M1: case Constants.LCONST_0: case Constants.LCONST_1: { break; } case Constants.BIPUSH: case Constants.SIPUSH: { ConstantPushInstruction cpi = (ConstantPushInstruction) inst; result.ints.add((Integer) cpi.getValue()); break; } // Primitive Binary operators. case Constants.DADD: case Constants.DCMPG: case Constants.DCMPL: case Constants.DDIV: case Constants.DMUL: case Constants.DREM: case Constants.DSUB: case Constants.FADD: case Constants.FCMPG: case Constants.FCMPL: case Constants.FDIV: case Constants.FMUL: case Constants.FREM: case Constants.FSUB: case Constants.IADD: case Constants.IAND: case Constants.IDIV: case Constants.IMUL: case Constants.IOR: case Constants.IREM: case Constants.ISHL: case Constants.ISHR: case Constants.ISUB: case Constants.IUSHR: case Constants.IXOR: case Constants.LADD: case Constants.LAND: case Constants.LCMP: case Constants.LDIV: case Constants.LMUL: case Constants.LOR: case Constants.LREM: case Constants.LSHL: case Constants.LSHR: case Constants.LSUB: case Constants.LUSHR: case Constants.LXOR: break; case Constants.LOOKUPSWITCH: case Constants.TABLESWITCH: break; case Constants.ANEWARRAY: case Constants.NEWARRAY: { break; } case Constants.MULTIANEWARRAY: { break; } // push the value at an index in an array case Constants.AALOAD: case Constants.BALOAD: case Constants.CALOAD: case Constants.DALOAD: case Constants.FALOAD: case Constants.IALOAD: case Constants.LALOAD: case Constants.SALOAD: { break; } // Pop the top of stack into an array location case Constants.AASTORE: case Constants.BASTORE: case Constants.CASTORE: case Constants.DASTORE: case Constants.FASTORE: case Constants.IASTORE: case Constants.LASTORE: case Constants.SASTORE: break; case Constants.ARETURN: case Constants.DRETURN: case Constants.FRETURN: case Constants.IRETURN: case Constants.LRETURN: case Constants.RETURN: { break; } // subroutine calls. case Constants.INVOKESTATIC: case Constants.INVOKEVIRTUAL: case Constants.INVOKESPECIAL: case Constants.INVOKEINTERFACE: break; // Throws an exception. case Constants.ATHROW: break; // Opcodes that don't need any modifications. Here for reference case Constants.ACONST_NULL: case Constants.ALOAD: case Constants.ALOAD_0: case Constants.ALOAD_1: case Constants.ALOAD_2: case Constants.ALOAD_3: case Constants.ASTORE: case Constants.ASTORE_0: case Constants.ASTORE_1: case Constants.ASTORE_2: case Constants.ASTORE_3: case Constants.CHECKCAST: case Constants.D2F: // double to float case Constants.D2I: // double to integer case Constants.D2L: // double to long case Constants.DNEG: // Negate double on top of stack case Constants.F2D: // float to double case Constants.F2I: // float to integer case Constants.F2L: // float to long case Constants.FNEG: // Negate float on top of stack case Constants.GOTO: case Constants.GOTO_W: case Constants.I2B: // integer to byte case Constants.I2C: // integer to char case Constants.I2D: // integer to double case Constants.I2F: // integer to float case Constants.I2L: // integer to long case Constants.I2S: // integer to short case Constants.IFNONNULL: case Constants.IFNULL: case Constants.IINC: // increment local variable by a constant case Constants.INEG: // negate integer on top of stack case Constants.JSR: // pushes return address on the stack, case Constants.JSR_W: case Constants.L2D: // long to double case Constants.L2F: // long to float case Constants.L2I: // long to int case Constants.LNEG: // negate long on top of stack case Constants.MONITORENTER: case Constants.MONITOREXIT: case Constants.NEW: case Constants.NOP: case Constants.RET: // this is the internal JSR return break; // Make sure we didn't miss anything default: throw new Error("instruction " + inst + " unsupported"); } } } } return result; }
/** * Given another class, return a transformed version of the class which replaces specified calls * with alternative static implementations */ public byte[] transform( ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { // debug = className.equals ("chicory/Test"); String fullClassName = className.replace("/", "."); debug_transform.log("In Transform: class = %s%n", className); // Don't instrument boot classes. We only want to instrument // user classes classpath. // Most boot classes have the null loader, // but some generated classes (such as those in sun.reflect) will // have a non-null loader. Some of these have a null parent loader, // but some do not. The check for the sun.reflect package is a hack // to catch all of these. A more consistent mechanism to determine // boot classes would be preferrable. if (loader == null) { debug_transform.log("ignoring system class %s, class loader == null", fullClassName); return (null); } else if (loader.getParent() == null) { debug_transform.log("ignoring system class %s, parent loader == null\n", fullClassName); return (null); } else if (fullClassName.startsWith("sun.reflect")) { debug_transform.log("ignoring system class %s, in sun.reflect package", fullClassName); return (null); } else if (fullClassName.startsWith("com.sun")) { System.out.printf("Class from com.sun package %s with nonnull loaders\n", fullClassName); } // Don't intrument our code if (className.startsWith("randoop.")) { debug_transform.log("Not considering randoop class %s%n", fullClassName); return (null); } // Look for match with specified regular expressions for class method_map = null; debug_class = false; for (MethodMapInfo mmi : map_list) { if (mmi.class_regex.matcher(className).matches()) { if (false && className.startsWith("RandoopTest")) debug_class = true; if (debug_class) System.out.printf("Classname %s matches re %s%n", className, mmi.class_regex); method_map = mmi.map; break; } } if (method_map == null) return null; debug_transform.log( "transforming class %s, loader %s - %s%n", className, loader, loader.getParent()); // Parse the bytes of the classfile, die on any errors JavaClass c = null; ClassParser parser = new ClassParser(new ByteArrayInputStream(classfileBuffer), className); try { c = parser.parse(); } catch (Exception e) { throw new RuntimeException("Unexpected error", e); } try { // Get the class information ClassGen cg = new ClassGen(c); ifact = new InstructionFactory(cg); map_calls(cg, className, loader); JavaClass njc = cg.getJavaClass(); if (debug) njc.dump("/tmp/ret/" + njc.getClassName() + ".class"); if (true) { return (cg.getJavaClass().getBytes()); } else { debug_transform.log("not including class %s (filtered out)", className); return null; } } catch (Throwable e) { out.format("Unexpected error %s in transform", e); e.printStackTrace(); return (null); } }
@Override public String toString() { return clazz.getClassName() + "." + method.getName(); }
public static double isDeepSerializable(JavaClass x) throws ClassNotFoundException { if (storedException != null) throw storedException; if (x.getClassName().equals("java.lang.Object")) return 0.4; if (DEBUG) { System.out.println("checking " + x.getClassName()); } double result = Analyze.deepInstanceOf(x, serializable); if (result >= 0.9) { if (DEBUG) { System.out.println("Direct high serializable result: " + result); } return result; } if (x.isFinal()) return result; double collectionResult = Analyze.deepInstanceOf(x, collection); double mapResult = Analyze.deepInstanceOf(x, map); if (x.isInterface() || x.isAbstract()) { result = Math.max(result, Math.max(mapResult, collectionResult) * 0.95); if (result >= 0.9) { return result; } } ClassDescriptor classDescriptor = DescriptorFactory.createClassDescriptor(x); Subtypes2 subtypes2 = AnalysisContext.currentAnalysisContext().getSubtypes2(); Set<ClassDescriptor> directSubtypes = subtypes2.getDirectSubtypes(classDescriptor); directSubtypes.remove(classDescriptor); double confidence = 0.6; if (x.isAbstract() || x.isInterface()) { confidence = 0.8; result = Math.max(result, 0.4); } else if (directSubtypes.isEmpty()) confidence = 0.2; double confidence2 = (1 + confidence) / 2; result = Math.max(result, confidence2 * collectionResult); if (result >= 0.9) { if (DEBUG) { System.out.println("High collection result: " + result); } return result; } result = Math.max(result, confidence2 * mapResult); if (result >= 0.9) { if (DEBUG) { System.out.println("High map result: " + result); } return result; } result = Math.max(result, confidence2 * 0.5 * Analyze.deepInstanceOf(x, comparator)); if (result >= 0.9) { if (DEBUG) { System.out.println("High comparator result: " + result); } return result; } for (ClassDescriptor subtype : directSubtypes) { JavaClass subJavaClass = Repository.lookupClass(subtype.getDottedClassName()); result = Math.max(result, confidence * Analyze.deepInstanceOf(subJavaClass, serializable)); // result = Math.max(result, confidence * isDeepSerializable(subJavaClass)); if (result >= 0.9) { return result; } } if (DEBUG) { System.out.println("No high results; max: " + result); } return result; }
@Override public void visitAfter(JavaClass obj) { if (isEnum) return; if (DEBUG) { System.out.println(getDottedClassName()); System.out.println(" hasPublicVoidConstructor: " + hasPublicVoidConstructor); System.out.println(" superClassHasVoidConstructor: " + superClassHasVoidConstructor); System.out.println(" isExternalizable: " + isExternalizable); System.out.println(" isSerializable: " + isSerializable); System.out.println(" isAbstract: " + isAbstract); System.out.println(" superClassImplementsSerializable: " + superClassImplementsSerializable); System.out.println(" isGUIClass: " + isGUIClass); System.out.println(" isEjbImplClass: " + isEjbImplClass); } if (isSerializable && !sawReadObject && !sawReadResolve && seenTransientField && !superClassHasReadObject) { for (Map.Entry<XField, Integer> e : transientFieldsUpdates.entrySet()) { XField fieldX = e.getKey(); int priority = NORMAL_PRIORITY; if (transientFieldsSetInConstructor.contains(e.getKey())) priority--; if (isGUIClass) priority++; if (isEjbImplClass) priority++; if (e.getValue() < 3) priority++; if (transientFieldsSetToDefaultValueInConstructor.contains(e.getKey())) priority++; if (obj.isAbstract()) { priority++; if (priority < Priorities.LOW_PRIORITY) priority = Priorities.LOW_PRIORITY; } try { double isSerializable = DeepSubtypeAnalysis.isDeepSerializable(fieldX.getSignature()); if (isSerializable < 0.6) priority++; } catch (ClassNotFoundException e1) { // ignore it } bugReporter.reportBug( new BugInstance(this, "SE_TRANSIENT_FIELD_NOT_RESTORED", priority) .addClass(getThisClass()) .addField(fieldX)); } } if (isSerializable && !isExternalizable && !superClassHasVoidConstructor && !superClassImplementsSerializable) { int priority = implementsSerializableDirectly || seenTransientField ? HIGH_PRIORITY : (sawSerialVersionUID ? NORMAL_PRIORITY : LOW_PRIORITY); if (isGUIClass) priority++; if (isEjbImplClass) priority++; bugReporter.reportBug( new BugInstance(this, "SE_NO_SUITABLE_CONSTRUCTOR", priority) .addClass(getThisClass().getClassName())); } // Downgrade class-level warnings if it's a GUI or EJB-implementation class. int priority = (isGUIClass || isEjbImplClass) ? LOW_PRIORITY : NORMAL_PRIORITY; if (obj.getClassName().endsWith("_Stub")) priority++; if (isExternalizable && !hasPublicVoidConstructor && !isAbstract) bugReporter.reportBug( new BugInstance( this, "SE_NO_SUITABLE_CONSTRUCTOR_FOR_EXTERNALIZATION", directlyImplementsExternalizable ? HIGH_PRIORITY : NORMAL_PRIORITY) .addClass(getThisClass().getClassName())); if (!foundSynthetic) priority++; if (seenTransientField) priority--; if (!isAnonymousInnerClass && !isExternalizable && !isGUIClass && !obj.isAbstract() && isSerializable && !isAbstract && !sawSerialVersionUID && !isEjbImplClass) bugReporter.reportBug( new BugInstance(this, "SE_NO_SERIALVERSIONID", priority).addClass(this)); if (writeObjectIsSynchronized && !foundSynchronizedMethods) bugReporter.reportBug( new BugInstance(this, "WS_WRITEOBJECT_SYNC", LOW_PRIORITY).addClass(this)); }
@Override public void visit(JavaClass obj) { String superClassname = obj.getSuperclassName(); // System.out.println("superclass of " + getClassName() + " is " + superClassname); isEnum = superClassname.equals("java.lang.Enum"); if (isEnum) return; int flags = obj.getAccessFlags(); isAbstract = (flags & ACC_ABSTRACT) != 0 || (flags & ACC_INTERFACE) != 0; isAnonymousInnerClass = anonymousInnerClassNamePattern.matcher(getClassName()).matches(); innerClassHasOuterInstance = false; for (Field f : obj.getFields()) { if (f.getName().equals("this$0")) { innerClassHasOuterInstance = true; break; } } sawSerialVersionUID = false; isSerializable = implementsSerializableDirectly = false; isExternalizable = false; directlyImplementsExternalizable = false; isGUIClass = false; isEjbImplClass = false; seenTransientField = false; // boolean isEnum = obj.getSuperclassName().equals("java.lang.Enum"); fieldsThatMightBeAProblem.clear(); transientFieldsUpdates.clear(); transientFieldsSetInConstructor.clear(); transientFieldsSetToDefaultValueInConstructor.clear(); // isRemote = false; // Does this class directly implement Serializable? String[] interface_names = obj.getInterfaceNames(); for (String interface_name : interface_names) { if (interface_name.equals("java.io.Externalizable")) { directlyImplementsExternalizable = true; isExternalizable = true; if (DEBUG) { System.out.println("Directly implements Externalizable: " + getClassName()); } } else if (interface_name.equals("java.io.Serializable")) { implementsSerializableDirectly = true; isSerializable = true; if (DEBUG) { System.out.println("Directly implements Serializable: " + getClassName()); } break; } } // Does this class indirectly implement Serializable? if (!isSerializable) { if (Subtypes2.instanceOf(obj, "java.io.Externalizable")) { isExternalizable = true; if (DEBUG) { System.out.println("Indirectly implements Externalizable: " + getClassName()); } } if (Subtypes2.instanceOf(obj, "java.io.Serializable")) { isSerializable = true; if (DEBUG) { System.out.println("Indirectly implements Serializable: " + getClassName()); } } } hasPublicVoidConstructor = false; superClassHasVoidConstructor = true; superClassHasReadObject = false; superClassImplementsSerializable = isSerializable && !implementsSerializableDirectly; ClassDescriptor superclassDescriptor = getXClass().getSuperclassDescriptor(); if (superclassDescriptor != null) try { XClass superXClass = Global.getAnalysisCache().getClassAnalysis(XClass.class, superclassDescriptor); if (superXClass != null) { superClassImplementsSerializable = AnalysisContext.currentAnalysisContext() .getSubtypes2() .isSubtype( superXClass.getClassDescriptor(), DescriptorFactory.createClassDescriptor(java.io.Serializable.class)); superClassHasVoidConstructor = false; for (XMethod m : superXClass.getXMethods()) { if (m.getName().equals("<init>") && m.getSignature().equals("()V") && !m.isPrivate()) { superClassHasVoidConstructor = true; } if (m.getName().equals("readObject") && m.getSignature().equals("(Ljava/io/ObjectInputStream;)V") && m.isPrivate()) superClassHasReadObject = true; } } } catch (ClassNotFoundException e) { bugReporter.reportMissingClass(e); } catch (CheckedAnalysisException e) { bugReporter.logError("huh", e); } // Is this a GUI or other class that is rarely serialized? isGUIClass = false; isEjbImplClass = false; if (true || !directlyImplementsExternalizable && !implementsSerializableDirectly) { isEjbImplClass = Subtypes2.instanceOf(obj, "javax.ejb.SessionBean"); isGUIClass = (Subtypes2.instanceOf(obj, "java.lang.Throwable") || Subtypes2.instanceOf(obj, "java.awt.Component") || Subtypes2.instanceOf(obj, "java.awt.Component$AccessibleAWTComponent") || Subtypes2.instanceOf(obj, "java.awt.event.ActionListener") || Subtypes2.instanceOf(obj, "java.util.EventListener")); if (!isGUIClass) { JavaClass o = obj; while (o != null) { if (o.getClassName().startsWith("java.awt") || o.getClassName().startsWith("javax.swing")) { isGUIClass = true; break; } try { o = o.getSuperClass(); } catch (ClassNotFoundException e) { break; } } } } foundSynthetic = false; foundSynchronizedMethods = false; writeObjectIsSynchronized = false; sawReadExternal = sawWriteExternal = sawReadObject = sawReadResolve = sawWriteObject = false; if (isSerializable) { for (Method m : obj.getMethods()) { if (m.getName().equals("readObject") && m.getSignature().equals("(Ljava/io/ObjectInputStream;)V")) sawReadObject = true; else if (m.getName().equals("readResolve") && m.getSignature().startsWith("()")) sawReadResolve = true; else if (m.getName().equals("readObjectNoData") && m.getSignature().equals("()V")) sawReadObject = true; else if (m.getName().equals("writeObject") && m.getSignature().equals("(Ljava/io/ObjectOutputStream;)V")) sawWriteObject = true; } for (Field f : obj.getFields()) { if (f.isTransient()) seenTransientField = true; } } }
protected void generateClassContext(JavaClass jc) { mPoolGen = new ConstantPoolGen(jc.getConstantPool()); mClassName = jc.getClassName(); mClassMetrics = mMetricsContainer.getMetrics(mClassName); }
/** * Construct a ClassDescriptor from a JavaClass. * * @param jclass a JavaClass * @return a ClassDescriptor identifying that JavaClass */ public static ClassDescriptor getClassDescriptor(JavaClass jclass) { return DescriptorFactory.instance() .getClassDescriptor(ClassName.toSlashedClassName(jclass.getClassName())); }
/** * overrides the visitor to report on classes without toStrings that have fields * * @param classContext the context object of the currently parsed class */ @Override public void visitClassContext(ClassContext classContext) { JavaClass cls = classContext.getJavaClass(); if (cls.getPackageName().isEmpty()) { bugReporter.reportBug( new BugInstance(this, BugType.IMC_IMMATURE_CLASS_NO_PACKAGE.name(), LOW_PRIORITY) .addClass(cls)); } if ((!cls.isAbstract()) && (!cls.isEnum()) && !cls.getClassName().contains("$") && !isTestClass(cls)) { try { boolean clsHasRuntimeAnnotation = classHasRuntimeVisibleAnnotation(cls); HEStatus heStatus = HEStatus.UNKNOWN; checkIDEGeneratedParmNames(cls); for (Field f : cls.getFields()) { if (!f.isStatic() && !f.isSynthetic()) { boolean fieldHasRuntimeAnnotation = fieldHasRuntimeVisibleAnnotation(f); if (!fieldHasRuntimeAnnotation) { /* only report one of these, so as not to flood the report */ if (!hasMethodInHierarchy(cls, "toString", "()Ljava/lang/String;")) { bugReporter.reportBug( new BugInstance( this, BugType.IMC_IMMATURE_CLASS_NO_TOSTRING.name(), LOW_PRIORITY) .addClass(cls)); return; } if (heStatus != HEStatus.NOT_NEEDED) { String fieldSig = f.getSignature(); if (fieldSig.startsWith("L")) { if (!fieldSig.startsWith("Ljava")) { JavaClass fieldClass = Repository.lookupClass(fieldSig.substring(1, fieldSig.length() - 1)); if (!hasMethodInHierarchy(fieldClass, "equals", "(Ljava/lang/Object)Z")) { heStatus = HEStatus.NOT_NEEDED; } } else if (!fieldSig.startsWith("Ljava/lang/") && !fieldSig.startsWith("Ljava/util/")) { heStatus = HEStatus.NOT_NEEDED; } } else if (!fieldSig.startsWith("[")) { heStatus = HEStatus.NEEDED; } } } else { heStatus = HEStatus.NOT_NEEDED; } } } if (!clsHasRuntimeAnnotation && (heStatus == HEStatus.NEEDED)) { if (!hasMethodInHierarchy(cls, "equals", "(Ljava/lang/Object;)Z")) { bugReporter.reportBug( new BugInstance(this, BugType.IMC_IMMATURE_CLASS_NO_EQUALS.name(), LOW_PRIORITY) .addClass(cls)); } else if (!hasMethodInHierarchy(cls, "hashCode", "()I")) { bugReporter.reportBug( new BugInstance(this, BugType.IMC_IMMATURE_CLASS_NO_HASHCODE.name(), LOW_PRIORITY) .addClass(cls)); } } } catch (ClassNotFoundException cnfe) { bugReporter.reportMissingClass(cnfe); } } }