@Override public MethodGen analyseInternal(final MethodGen methodGen) { assert methodGen != null : "Parameter 'methodGen' of method 'analyseInternal' must not be null"; if (!methodGen.getMethod().isAbstract() && null != methodGen.getInstructionList()) { final List<InstructionHandle> instnsHandleList = Arrays.asList(methodGen.getInstructionList().getInstructionHandles()); instnsHandleList.forEach(t -> analyseAsVisiting(t, methodGen)); return methodGen; } return null; }
@Override public void visitClassContext(ClassContext classContext) { JavaClass javaClass = classContext.getJavaClass(); Method[] methodList = javaClass.getMethods(); for (Method m : methodList) { MethodGen methodGen = classContext.getMethodGen(m); if (DEBUG) { System.out.println(">>> Method: " + m.getName()); } // To suspect that an invalid String representation is being build, // we identify the construction of a MessageDigest and // the use of a function that trim leading 0. boolean invokeMessageDigest = false; boolean invokeToHexString = false; ConstantPoolGen cpg = classContext.getConstantPoolGen(); if (methodGen == null || methodGen.getInstructionList() == null) { continue; // No instruction .. nothing to do } for (Iterator itIns = methodGen.getInstructionList().iterator(); itIns.hasNext(); ) { Instruction inst = ((InstructionHandle) itIns.next()).getInstruction(); if (DEBUG) { ByteCode.printOpCode(inst, cpg); } if (inst instanceof INVOKEVIRTUAL) { // MessageDigest.digest is called INVOKEVIRTUAL invoke = (INVOKEVIRTUAL) inst; if ("java.security.MessageDigest".equals(invoke.getClassName(cpg)) && "digest".equals(invoke.getMethodName(cpg))) { invokeMessageDigest = true; } } else if (inst instanceof INVOKESTATIC && invokeMessageDigest) { // The conversion must occurs after the digest was created INVOKESTATIC invoke = (INVOKESTATIC) inst; if ("java.lang.Integer".equals(invoke.getClassName(cpg)) && "toHexString".equals(invoke.getMethodName(cpg))) { invokeToHexString = true; } } } if (invokeMessageDigest && invokeToHexString) { bugReporter.reportBug( new BugInstance(this, BAD_HEXA_CONVERSION_TYPE, Priorities.NORMAL_PRIORITY) // .addClassAndMethod(javaClass, m)); } } }
/** * Runs through specified class and find index of method specified by methodName. The index is * than used as key to obtain handlers. Note: Not the best solution * * @param fullyQualifiedClassName * @param methodName * @return */ private InstructionList provideHandlersToMethod( String fullyQualifiedClassName, String methodName) { InstructionList handlers = null; try { JavaClass cl = Repository.lookupClass(fullyQualifiedClassName); ClassGen cg = new ClassGen(cl); Method[] methods = cg.getMethods(); int methodIndex = 0; for (int i = 0; i < methods.length; i++) { if (methods[i].getName().equals(methodName)) { methodIndex = i; } } MethodGen mg = new MethodGen(cg.getMethodAt(methodIndex), null, cg.getConstantPool()); handlers = mg.getInstructionList(); } catch (ClassNotFoundException ex) { Logger.getLogger(BugPatternDetectorImpl.class.getName()) .log( Level.SEVERE, "The method " + methodName + " was not found in " + fullyQualifiedClassName + " class."); } return handlers; }
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; }
byte[] nullAdaptClass(final InputStream is, final String name) throws Exception { JavaClass jc = new ClassParser(is, name + ".class").parse(); ClassGen cg = new ClassGen(jc); String cName = cg.getClassName(); ConstantPoolGen cp = cg.getConstantPool(); Method[] ms = cg.getMethods(); for (int j = 0; j < ms.length; ++j) { MethodGen mg = new MethodGen(ms[j], cg.getClassName(), cp); boolean lv = ms[j].getLocalVariableTable() == null; boolean ln = ms[j].getLineNumberTable() == null; if (lv) { mg.removeLocalVariables(); } if (ln) { mg.removeLineNumbers(); } mg.stripAttributes(skipDebug); InstructionList il = mg.getInstructionList(); if (il != null) { InstructionHandle ih = il.getStart(); while (ih != null) { ih = ih.getNext(); } if (compute) { mg.setMaxStack(); mg.setMaxLocals(); } } cg.replaceMethod(ms[j], mg.getMethod()); } return cg.getJavaClass().getBytes(); }
/** Checks the specific method for consistency. */ public static void checkMgen(MethodGen mgen) { if (skip_checks) return; try { mgen.toString(); mgen.getLineNumberTable(mgen.getConstantPool()); InstructionList ilist = mgen.getInstructionList(); if (ilist == null || ilist.getStart() == null) return; CodeExceptionGen[] exceptionHandlers = mgen.getExceptionHandlers(); for (CodeExceptionGen gen : exceptionHandlers) { assert ilist.contains(gen.getStartPC()) : "exception handler " + gen + " has been forgotten in " + mgen.getClassName() + "." + mgen.getName(); } MethodGen nmg = new MethodGen(mgen.getMethod(), mgen.getClassName(), mgen.getConstantPool()); nmg.getLineNumberTable(mgen.getConstantPool()); } catch (Throwable t) { System.out.printf("failure in method %s.%s\n", mgen.getClassName(), mgen.getName()); t.printStackTrace(); throw new Error(t); } }
public SearchResult run(RSClient data, HashMap<String, ClassGen> classes) { for (ClassGen c : classes.values()) { ConstantPoolGen cpg = c.getConstantPool(); if (cpg.lookupFloat(16384.0000f) != -1) { for (Method m : c.getMethods()) { if (m.isStatic()) { MethodGen gen = new MethodGen(m, c.getClassName(), cpg); InstructionList il = gen.getInstructionList(); if (il == null) continue; InstructionFinder f = new InstructionFinder(il); Iterator e = f.search("GETSTATIC LDC FSUB PUTSTATIC"); if (e.hasNext()) { InstructionHandle[] handles = (InstructionHandle[]) e.next(); data.addField( "MapAngle", ((GETSTATIC) handles[0].getInstruction()).getClassName(cpg) + "." + ((GETSTATIC) handles[0].getInstruction()).getFieldName(cpg)); return SearchResult.Success; } } } } } return SearchResult.Failure; }
/** Instrument the specified method to replace mapped calls. */ public void instrument_method(Method m, MethodGen mg) { // Loop through each instruction, making substitutions InstructionList il = mg.getInstructionList(); for (InstructionHandle ih = il.getStart(); ih != null; ) { if (debug_instrument_inst.enabled()) { debug_instrument_inst.log("instrumenting instruction %s%n", ih); // ih.getInstruction().toString(pool.getConstantPool())); } InstructionList new_il = null; // Remember the next instruction to process InstructionHandle next_ih = ih.getNext(); // Get the translation for this instruction (if any) new_il = xform_inst(mg, ih.getInstruction()); if (debug_instrument_inst.enabled()) debug_instrument_inst.log(" new inst: %s%n", new_il); // If this instruction was modified, replace it with the new // instruction list. If this instruction was the target of any // jumps or line numbers , replace them with the first // instruction in the new list replace_instructions(il, ih, new_il); ih = next_ih; } }
/** * TODO * * @param mg */ public StackTypes(MethodGen mg) { InstructionList il = mg.getInstructionList(); int size = 0; if (il != null) size = il.getEnd().getPosition(); os_arr = new OperandStack[size + 1]; if (track_locals) loc_arr = new LocalVariables[size + 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(); } }
/** * Transforms the init method to create the newly added join point member field. * * @param cp the ConstantPoolGen * @param cg the ClassGen * @param init the constructor for the class * @param method the current method * @param factory the objectfactory * @param methodSequence the methods sequence number * @return the modified constructor */ private MethodGen createJoinPointField( final ConstantPoolGen cp, final ClassGen cg, final Method init, final Method method, final InstructionFactory factory, final int methodSequence) { final MethodGen mg = new MethodGen(init, cg.getClassName(), cp); final InstructionList il = mg.getInstructionList(); final InstructionHandle[] ihs = il.getInstructionHandles(); // grab the handle to the the return instruction of the constructor InstructionHandle ih = ihs[0]; for (int i = 0; i < ihs.length; i++) { Instruction instruction = ihs[i].getInstruction(); if (instruction instanceof ReturnInstruction) { ih = ihs[i]; // set the instruction handle to the return instruction break; } } final String joinPoint = getJoinPointName(method, methodSequence); final InstructionHandle ihPost; ihPost = il.insert(ih, factory.createLoad(Type.OBJECT, 0)); il.insert(ih, factory.createNew(TransformationUtil.THREAD_LOCAL_CLASS)); il.insert(ih, InstructionConstants.DUP); il.insert( ih, factory.createInvoke( TransformationUtil.THREAD_LOCAL_CLASS, "<init>", Type.VOID, new Type[] {}, Constants.INVOKESPECIAL)); il.insert( ih, factory.createFieldAccess( cg.getClassName(), joinPoint, new ObjectType(TransformationUtil.THREAD_LOCAL_CLASS), Constants.PUTFIELD)); il.redirectBranches(ih, ihPost); mg.setMaxStack(); mg.setMaxLocals(); return mg; }
byte[] counterAdaptClass(final InputStream is, final String name) throws Exception { JavaClass jc = new ClassParser(is, name + ".class").parse(); ClassGen cg = new ClassGen(jc); String cName = cg.getClassName(); ConstantPoolGen cp = cg.getConstantPool(); if (!cg.isInterface()) { FieldGen fg = new FieldGen(ACC_PUBLIC, Type.getType("I"), "_counter", cp); cg.addField(fg.getField()); } Method[] ms = cg.getMethods(); for (int j = 0; j < ms.length; ++j) { MethodGen mg = new MethodGen(ms[j], cg.getClassName(), cp); if (!mg.getName().equals("<init>") && !mg.isStatic() && !mg.isAbstract() && !mg.isNative()) { if (mg.getInstructionList() != null) { InstructionList il = new InstructionList(); il.append(new ALOAD(0)); il.append(new ALOAD(0)); il.append(new GETFIELD(cp.addFieldref(name, "_counter", "I"))); il.append(new ICONST(1)); il.append(new IADD()); il.append(new PUTFIELD(cp.addFieldref(name, "_counter", "I"))); mg.getInstructionList().insert(il); mg.setMaxStack(Math.max(mg.getMaxStack(), 2)); boolean lv = ms[j].getLocalVariableTable() == null; boolean ln = ms[j].getLineNumberTable() == null; if (lv) { mg.removeLocalVariables(); } if (ln) { mg.removeLineNumbers(); } cg.replaceMethod(ms[j], mg.getMethod()); } } } return cg.getJavaClass().getBytes(); }
/* * (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; }
/** Adds code in nl to start of method mg * */ public static void add_to_start(MethodGen mg, InstructionList nl) { // Add the code before the first instruction InstructionList il = mg.getInstructionList(); InstructionHandle old_start = il.getStart(); InstructionHandle new_start = il.insert(nl); // Move any LineNumbers and local variable that currently point to // the first instruction to include the new instructions. Other // targeters (branches, exceptions) should not include the new // code if (old_start.hasTargeters()) { for (InstructionTargeter it : old_start.getTargeters()) { if ((it instanceof LineNumberGen) || (it instanceof LocalVariableGen)) it.updateTarget(old_start, new_start); } } mg.setMaxStack(); mg.setMaxLocals(); }
static void nullBCELAdapt(final byte[] b) throws IOException { JavaClass jc = new ClassParser(new ByteArrayInputStream(b), "class-name").parse(); ClassGen cg = new ClassGen(jc); ConstantPoolGen cp = cg.getConstantPool(); Method[] ms = cg.getMethods(); for (int k = 0; k < ms.length; ++k) { MethodGen mg = new MethodGen(ms[k], cg.getClassName(), cp); boolean lv = ms[k].getLocalVariableTable() == null; boolean ln = ms[k].getLineNumberTable() == null; if (lv) { mg.removeLocalVariables(); } if (ln) { mg.removeLineNumbers(); } mg.stripAttributes(skipDebug); InstructionList il = mg.getInstructionList(); if (il != null) { InstructionHandle ih = il.getStart(); while (ih != null) { ih = ih.getNext(); } if (compute) { mg.setMaxStack(); mg.setMaxLocals(); } if (computeFrames) { ModifiedPass3bVerifier verif; verif = new ModifiedPass3bVerifier(jc, k); verif.do_verify(); } } cg.replaceMethod(ms[k], mg.getMethod()); } cg.getJavaClass().getBytes(); }
/** * 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; }
/** * Processes each method in cg replacing any specified calls with static user calls. * * @param fullClassName must be packageName.className */ private boolean map_calls(ClassGen cg, String fullClassName, ClassLoader loader) { boolean transformed = false; try { pgen = cg.getConstantPool(); // Loop through each method in the class Method[] methods = cg.getMethods(); for (int i = 0; i < methods.length; i++) { MethodGen mg = new MethodGen(methods[i], cg.getClassName(), pgen); // Get the instruction list and skip methods with no instructions InstructionList il = mg.getInstructionList(); if (il == null) continue; if (debug) out.format("Original code: %s%n", mg.getMethod().getCode()); instrument_method(methods[i], mg); // Remove the Local variable type table attribute (if any). // Evidently, some changes we make require this to be updated, but // without BCEL support, that would be hard to do. Just delete it // for now (since it is optional, and we are unlikely to be used by // a debugger) for (Attribute a : mg.getCodeAttributes()) { if (is_local_variable_type_table(a)) { mg.removeCodeAttribute(a); } } // Update the instruction list mg.setInstructionList(il); mg.update(); // Update the max stack and Max Locals mg.setMaxLocals(); mg.setMaxStack(); mg.update(); // Update the method in the class cg.replaceMethod(methods[i], mg.getMethod()); if (debug) out.format("Modified code: %s%n", mg.getMethod().getCode()); // verify the new method // StackVer stackver = new StackVer(); // VerificationResult vr = stackver.do_stack_ver (mg); // log ("vr for method %s = %s%n", mg.getName(), vr); // if (vr.getStatus() != VerificationResult.VERIFIED_OK) { // System.out.printf ("Warning BCEL Verify failed for method %s: %s", // mg.getName(), vr); // System.out.printf ("Code: %n%s%n", mg.getMethod().getCode()); // System.exit(1); // } } cg.update(); } catch (Exception e) { out.format("Unexpected exception encountered: " + e); e.printStackTrace(); } return transformed; }
/** * 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; }
/** * Constructor. * * @param il A MethodGen object representing method to create the Subroutine objects of. */ public Subroutines(MethodGen mg) { InstructionHandle[] all = mg.getInstructionList().getInstructionHandles(); CodeExceptionGen[] handlers = mg.getExceptionHandlers(); // Define our "Toplevel" fake subroutine. TOPLEVEL = new SubroutineImpl(); // Calculate "real" subroutines. HashSet<InstructionHandle> sub_leaders = new HashSet<InstructionHandle>(); // Elements: InstructionHandle for (int i = 0; i < all.length; i++) { Instruction inst = all[i].getInstruction(); if (inst instanceof JsrInstruction) { sub_leaders.add(((JsrInstruction) inst).getTarget()); } } // Build up the database. Iterator iter = sub_leaders.iterator(); while (iter.hasNext()) { SubroutineImpl sr = new SubroutineImpl(); InstructionHandle astore = (InstructionHandle) (iter.next()); sr.setLocalVariable(((ASTORE) (astore.getInstruction())).getIndex()); subroutines.put(astore, sr); } // Fake it a bit. We want a virtual "TopLevel" subroutine. subroutines.put(all[0], TOPLEVEL); sub_leaders.add(all[0]); // Tell the subroutines about their JsrInstructions. // Note that there cannot be a JSR targeting the top-level // since "Jsr 0" is disallowed in Pass 3a. // Instructions shared by a subroutine and the toplevel are // disallowed and checked below, after the BFS. for (int i = 0; i < all.length; i++) { Instruction inst = all[i].getInstruction(); if (inst instanceof JsrInstruction) { InstructionHandle leader = ((JsrInstruction) inst).getTarget(); ((SubroutineImpl) getSubroutine(leader)).addEnteringJsrInstruction(all[i]); } } // Now do a BFS from every subroutine leader to find all the // instructions that belong to a subroutine. HashSet<InstructionHandle> instructions_assigned = new HashSet<InstructionHandle>(); // we don't want to assign an instruction to two or more // Subroutine objects. Hashtable<InstructionHandle, Color> colors = new Hashtable< InstructionHandle, Color>(); // Graph colouring. Key: InstructionHandle, Value: java.awt.Color . iter = sub_leaders.iterator(); while (iter.hasNext()) { // Do some BFS with "actual" as the root of the graph. InstructionHandle actual = (InstructionHandle) (iter.next()); // Init colors for (int i = 0; i < all.length; i++) { colors.put(all[i], Color.white); } colors.put(actual, Color.gray); // Init Queue ArrayList<InstructionHandle> Q = new ArrayList<InstructionHandle>(); Q.add(actual); // add(Obj) adds to the end, remove(0) removes from the start. /* BFS ALGORITHM MODIFICATION: Start out with multiple "root" nodes, as exception handlers are starting points of top-level code, too. [why top-level? TODO: Refer to the special JustIce notion of subroutines.]*/ if (actual == all[0]) { for (int j = 0; j < handlers.length; j++) { colors.put(handlers[j].getHandlerPC(), Color.gray); Q.add(handlers[j].getHandlerPC()); } } /* CONTINUE NORMAL BFS ALGORITHM */ // Loop until Queue is empty while (Q.size() != 0) { InstructionHandle u = (InstructionHandle) Q.remove(0); InstructionHandle[] successors = getSuccessors(u); for (int i = 0; i < successors.length; i++) { if (((Color) colors.get(successors[i])) == Color.white) { colors.put(successors[i], Color.gray); Q.add(successors[i]); } } colors.put(u, Color.black); } // BFS ended above. for (int i = 0; i < all.length; i++) { if (colors.get(all[i]) == Color.black) { ((SubroutineImpl) (actual == all[0] ? getTopLevel() : getSubroutine(actual))) .addInstruction(all[i]); if (instructions_assigned.contains(all[i])) { throw new StructuralCodeConstraintException( "Instruction '" + all[i] + "' is part of more than one subroutine (or of the top level and a subroutine)."); } else { instructions_assigned.add(all[i]); } } } if (actual != all[0]) { // If we don't deal with the top-level 'subroutine' ((SubroutineImpl) getSubroutine(actual)).setLeavingRET(); } } // Now make sure no instruction of a Subroutine is protected by exception handling code // as is mandated by JustIces notion of subroutines. for (int i = 0; i < handlers.length; i++) { InstructionHandle _protected = handlers[i].getStartPC(); while (_protected != handlers[i] .getEndPC() .getNext()) { // Note the inclusive/inclusive notation of "generic API" exception // handlers! Enumeration subs = subroutines.elements(); while (subs.hasMoreElements()) { Subroutine sub = (Subroutine) subs.nextElement(); if (sub != subroutines.get(all[0])) { // We don't want to forbid top-level exception handlers. if (sub.contains(_protected)) { throw new StructuralCodeConstraintException( "Subroutine instruction '" + _protected + "' is protected by an exception handler, '" + handlers[i] + "'. This is forbidden by the JustIce verifier due to its clear definition of subroutines."); } } } _protected = _protected.getNext(); } } // Now make sure no subroutine is calling a subroutine // that uses the same local variable for the RET as themselves // (recursively). // This includes that subroutines may not call themselves // recursively, even not through intermediate calls to other // subroutines. noRecursiveCalls(getTopLevel(), new HashSet<Integer>()); }