@Override public void transferInstruction(InstructionHandle handle, BasicBlock basicBlock, LockSet fact) throws DataflowAnalysisException { Instruction ins = handle.getInstruction(); short opcode = ins.getOpcode(); if (opcode == Constants.MONITORENTER || opcode == Constants.MONITOREXIT) { ValueNumberFrame frame = vnaDataflow.getFactAtLocation(new Location(handle, basicBlock)); modifyLock(frame, fact, opcode == Constants.MONITORENTER ? 1 : -1); } else if (opcode == Constants.INVOKEVIRTUAL || opcode == Constants.INVOKEINTERFACE) { InvokeInstruction inv = (InvokeInstruction) ins; String name = inv.getMethodName(methodGen.getConstantPool()); String sig = inv.getSignature(methodGen.getConstantPool()); ValueNumberFrame frame = vnaDataflow.getFactAtLocation(new Location(handle, basicBlock)); if ("()V".equals(sig) && ("lock".equals(name) || "lockInterruptibly".equals(name))) { modifyLock(frame, fact, 1); } else if ("()V".equals(sig) && ("unlock".equals(name))) { modifyLock(frame, fact, -1); } } else if ((ins instanceof ReturnInstruction) && isSynchronized && !isStatic) { lockOp(fact, vna.getThisValue().getNumber(), -1); } }
/** Start the method's visit. */ public void start() { if (!mg.isAbstract() && !mg.isNative()) { for (InstructionHandle ih = mg.getInstructionList().getStart(); ih != null; ih = ih.getNext()) { Instruction i = ih.getInstruction(); if (!visitInstruction(i)) i.accept(this); } updateExceptionHandlers(); } }
CFG createCFG(String className) throws ClassNotFoundException { CFG cfg = new CFG(); JavaClass jc = Repository.lookupClass(className); ClassGen cg = new ClassGen(jc); ConstantPoolGen cpg = cg.getConstantPool(); for (Method m : cg.getMethods()) { MethodGen mg = new MethodGen(m, cg.getClassName(), cpg); InstructionList il = mg.getInstructionList(); InstructionHandle[] handles = il.getInstructionHandles(); int prev = 0; for (InstructionHandle ih : handles) { int position = ih.getPosition(); cfg.addNode(position, m, jc); Instruction inst = ih.getInstruction(); boolean br = inst.getName().contains("if") || inst.getName().contains("goto"); boolean ret = inst.getName().contains("return"); boolean stat = inst.getName().contains("invokestatic"); int len = inst.getLength(); if (stat) { int index = inst.toString(true).indexOf(" "); String name = inst.toString(true).substring(index + 1); int tar = Integer.valueOf(name); INVOKESTATIC inv = new INVOKESTATIC(tar); name = inv.getMethodName(cpg); Method m2 = null; Method[] tm = cg.getMethods(); for (int i = 0; i < tm.length; i++) { if (tm[i].getName().equals(name)) { m2 = tm[i]; } } cfg.addEdge(position, m, jc, 0, m2, jc); cfg.addEdge(-1, m2, jc, position + len, m, jc); } if (!ret && !stat) { cfg.addEdge(position, position + len, m, jc); } if (br) { cfg.addEdge(position, position + len, m, jc); IF_ICMPGE comp = new IF_ICMPGE(ih); String name = comp.getTarget().toString(false); int index = name.indexOf(">"); name = name.substring(index + 2); int tar = Integer.valueOf(name); cfg.addEdge(position, tar, m, jc); } if (ret) { cfg.addEdge(position, -1, m, jc); } prev = position; } System.out.println(cfg.toString()); } return cfg; }
/** Visit a single instruction. */ private boolean visitInstruction(Instruction i) { short opcode = i.getOpcode(); return ((InstructionConstants.INSTRUCTIONS[opcode] != null) && !(i instanceof ConstantPushInstruction) && !(i instanceof ReturnInstruction)); }
/* * (non-Javadoc) * * @see * edu.umd.cs.findbugs.classfile.IAnalysisEngine#analyze(edu.umd.cs.findbugs * .classfile.IAnalysisCache, java.lang.Object) */ public LoadedFieldSet analyze(IAnalysisCache analysisCache, MethodDescriptor descriptor) throws CheckedAnalysisException { MethodGen methodGen = getMethodGen(analysisCache, descriptor); if (methodGen == null) return null; InstructionList il = methodGen.getInstructionList(); LoadedFieldSet loadedFieldSet = new LoadedFieldSet(methodGen); ConstantPoolGen cpg = getConstantPoolGen(analysisCache, descriptor.getClassDescriptor()); for (InstructionHandle handle = il.getStart(); handle != null; handle = handle.getNext()) { Instruction ins = handle.getInstruction(); short opcode = ins.getOpcode(); try { if (opcode == Constants.INVOKESTATIC) { INVOKESTATIC inv = (INVOKESTATIC) ins; if (Hierarchy.isInnerClassAccess(inv, cpg)) { InnerClassAccess access = Hierarchy.getInnerClassAccess(inv, cpg); /* * if (access == null) { * System.out.println("Missing inner class access in " + * SignatureConverter.convertMethodSignature(methodGen) * + " at " + inv); } */ if (access != null) { if (access.isLoad()) loadedFieldSet.addLoad(handle, access.getField()); else loadedFieldSet.addStore(handle, access.getField()); } } } else if (fieldInstructionOpcodeSet.get(opcode)) { boolean isLoad = (opcode == Constants.GETFIELD || opcode == Constants.GETSTATIC); XField field = Hierarchy.findXField((FieldInstruction) ins, cpg); if (field != null) { if (isLoad) loadedFieldSet.addLoad(handle, field); else loadedFieldSet.addStore(handle, field); } } } catch (ClassNotFoundException e) { AnalysisContext.currentAnalysisContext().getLookupFailureCallback().reportMissingClass(e); } } return loadedFieldSet; }
/** * Determine if given Instruction is a monitor wait. * * @param ins the Instruction * @param cpg the ConstantPoolGen for the Instruction * @return true if the instruction is a monitor wait, false if not */ public static boolean isMonitorNotify(Instruction ins, ConstantPoolGen cpg) { if (!(ins instanceof InvokeInstruction)) return false; if (ins.getOpcode() == Constants.INVOKESTATIC) return false; InvokeInstruction inv = (InvokeInstruction) ins; String methodName = inv.getMethodName(cpg); String methodSig = inv.getSignature(cpg); return isMonitorNotify(methodName, methodSig); }
@Override public void visitInstructionHandle(InstructionHandle handle) { try { Instruction ins = handle.getInstruction(); short opcode = ins.getOpcode(); if (DEBUG) System.out.printf("%3d %s%n", handle.getPosition(), Constants.OPCODE_NAMES[opcode]); if (opcode == Constants.PUTFIELD || opcode == Constants.PUTSTATIC || opcode == Constants.ARETURN) { // // A value is being assigned to a field or returned from // the method. // Location loc = new Location(handle, curBlock); TypeFrame typeFrame = typeDataflow.getFactAtLocation(loc); if (!typeFrame.isValid()) { // dead code? couldNotAnalyze = true; } Type tosType = typeFrame.getTopValue(); if (tosType instanceof ObjectType && isPossibleInstanceOfObligationType( subtypes2, (ObjectType) tosType, possiblyLeakedObligation.getType())) { // Remove one obligation of this type adjustedLeakCount--; if (DEBUG) System.out.println( "removing obligation to close " + tosType + " at " + handle.getPosition()); } } if (COMPUTE_TRANSFERS && ins instanceof InvokeInstruction) { checkForPossibleObligationTransfer((InvokeInstruction) ins, handle); } } catch (ClassNotFoundException e) { bugReporter.reportMissingClass(e); couldNotAnalyze = true; } catch (DataflowAnalysisException e) { couldNotAnalyze = true; } }
/* 70: */ /* 71: */ public static final Instruction readInstruction(ByteSequence bytes) /* 72: */ throws IOException /* 73: */ { /* 74:167 */ boolean wide = false; /* 75:168 */ short opcode = (short) bytes.readUnsignedByte(); /* 76:169 */ Instruction obj = null; /* 77:171 */ if (opcode == 196) /* 78: */ { /* 79:172 */ wide = true; /* 80:173 */ opcode = (short) bytes.readUnsignedByte(); /* 81: */ } /* 82:176 */ if (InstructionConstants.INSTRUCTIONS[opcode] != null) { /* 83:177 */ return InstructionConstants.INSTRUCTIONS[opcode]; /* 84: */ } /* 85: */ Class clazz; /* 86: */ try /* 87: */ { /* 88:184 */ clazz = Class.forName(className(opcode)); /* 89: */ } /* 90: */ catch (ClassNotFoundException cnfe) /* 91: */ { /* 92:189 */ throw new ClassGenException("Illegal opcode detected."); /* 93: */ } /* 94: */ try /* 95: */ { /* 96:192 */ obj = (Instruction) clazz.newInstance(); /* 97:194 */ if ((wide) && (!(obj instanceof LocalVariableInstruction)) && (!(obj instanceof IINC)) && (!(obj instanceof RET))) { /* 98:196 */ throw new Exception("Illegal opcode after wide: " + opcode); /* 99: */ } /* 100:198 */ obj.setOpcode(opcode); /* 101:199 */ obj.initFromFile(bytes, wide); /* 102: */ } /* 103: */ catch (Exception e) /* 104: */ { /* 105:201 */ throw new ClassGenException(e.toString()); /* 106: */ } /* 107:203 */ return obj; /* 108: */ }
/** * Transforms invoke instructions that match the specified list for this class to call the * specified static call instead. */ private InstructionList xform_inst(MethodGen mg, Instruction inst) { switch (inst.getOpcode()) { case Constants.INVOKESTATIC: { InstructionList il = new InstructionList(); INVOKESTATIC is = (INVOKESTATIC) inst; String cname = is.getClassName(pgen); String mname = is.getMethodName(pgen); Type[] args = is.getArgumentTypes(pgen); MethodDef orig = new MethodDef(cname + "." + mname, args); MethodInfo call = method_map.get(orig); if (call != null) { call.cnt++; String classname = call.method_class; String methodname = mname; debug_map.log( "%s.%s: Replacing method %s.%s (%s) with %s.%s%n", mg.getClassName(), mg.getName(), cname, mname, UtilMDE.join(args, ", "), classname, methodname); il.append( ifact.createInvoke( classname, methodname, is.getReturnType(pgen), args, Constants.INVOKESTATIC)); } return (il); } case Constants.INVOKEVIRTUAL: { InstructionList il = new InstructionList(); INVOKEVIRTUAL iv = (INVOKEVIRTUAL) inst; String cname = iv.getClassName(pgen); String mname = iv.getMethodName(pgen); Type[] args = iv.getArgumentTypes(pgen); Type instance_type = iv.getReferenceType(pgen); Type[] new_args = BCELUtil.insert_type(instance_type, args); MethodDef orig = new MethodDef(cname + "." + mname, args); if (debug_class) System.out.printf("looking for %s in map %s%n", orig, method_map); MethodInfo call = method_map.get(orig); if (call != null) { call.cnt++; String classname = call.method_class; String methodname = mname; debug_map.log( "Replacing method %s.%s (%s) with %s.%s%n", cname, mname, ArraysMDE.toString(args), classname, methodname); il.append( ifact.createInvoke( classname, methodname, iv.getReturnType(pgen), new_args, Constants.INVOKESTATIC)); } return (il); } default: return (null); } }
/** * 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; }