public Value naryOperation(final AbstractInsnNode insn, final List values) throws AnalyzerException { int opcode = insn.getOpcode(); if (opcode == MULTIANEWARRAY) { for (int i = 0; i < values.size(); ++i) { if (values.get(i) != BasicValue.INT_VALUE) { throw new AnalyzerException(null, BasicValue.INT_VALUE, (Value) values.get(i)); } } } else { int i = 0; int j = 0; if (opcode != INVOKESTATIC) { Type owner = Type.getType("L" + ((MethodInsnNode) insn).owner + ";"); if (!isSubTypeOf((Value) values.get(i++), newValue(owner))) { throw new AnalyzerException("Method owner", newValue(owner), (Value) values.get(0)); } } Type[] args = Type.getArgumentTypes(((MethodInsnNode) insn).desc); while (i < values.size()) { Value expected = newValue(args[j++]); Value encountered = (Value) values.get(i++); if (!isSubTypeOf(encountered, expected)) { throw new AnalyzerException("Argument " + j, expected, encountered); } } } return super.naryOperation(insn, values); }
public Value ternaryOperation( final AbstractInsnNode insn, final Value value1, final Value value2, final Value value3) throws AnalyzerException { Value expected1; Value expected3; switch (insn.getOpcode()) { case IASTORE: case BASTORE: case CASTORE: case SASTORE: expected1 = newValue(Type.getType("[I")); expected3 = BasicValue.INT_VALUE; break; case LASTORE: expected1 = newValue(Type.getType("[J")); expected3 = BasicValue.LONG_VALUE; break; case FASTORE: expected1 = newValue(Type.getType("[F")); expected3 = BasicValue.FLOAT_VALUE; break; case DASTORE: expected1 = newValue(Type.getType("[D")); expected3 = BasicValue.DOUBLE_VALUE; break; case AASTORE: expected1 = value1; expected3 = getElementValue(value1); break; default: throw new RuntimeException("Internal error."); } if (!isSubTypeOf(value1, expected1)) { throw new AnalyzerException("First argument", "a " + expected1 + " array reference", value1); } else if (value2 != BasicValue.INT_VALUE) { throw new AnalyzerException("Second argument", BasicValue.INT_VALUE, value2); } else if (!isSubTypeOf(value3, expected3)) { throw new AnalyzerException("Third argument", expected3, value3); } return null; }
public Value copyOperation(final AbstractInsnNode insn, final Value value) throws AnalyzerException { Value expected; switch (insn.getOpcode()) { case ILOAD: case ISTORE: expected = BasicValue.INT_VALUE; break; case FLOAD: case FSTORE: expected = BasicValue.FLOAT_VALUE; break; case LLOAD: case LSTORE: expected = BasicValue.LONG_VALUE; break; case DLOAD: case DSTORE: expected = BasicValue.DOUBLE_VALUE; break; case ALOAD: if (!((BasicValue) value).isReference()) { throw new AnalyzerException(null, "an object reference", value); } return value; case ASTORE: if (!((BasicValue) value).isReference() && value != BasicValue.RETURNADDRESS_VALUE) { throw new AnalyzerException(null, "an object reference or a return address", value); } return value; default: return value; } // type is necessarily a primitive type here, // so value must be == to expected value if (value != expected) { throw new AnalyzerException(null, expected, value); } return value; }
/** * Analyzes the given method. * * @param c the class to which the method belongs. * @param m the method to be analyzed. * @return the symbolic state of the execution stack frame at each bytecode instruction of the * method. The size of the returned array is equal to the number of instructions (and labels) * of the method. A given frame is <tt>null</tt> if and only if the corresponding instruction * cannot be reached (dead code). * @throws AnalyzerException if a problem occurs during the analysis. */ public Frame[] analyze(final ClassNode c, final MethodNode m) throws AnalyzerException { n = m.instructions.size(); indexes = new IntMap(2 * n); handlers = new List[n]; frames = new Frame[n]; subroutines = new Subroutine[n]; queued = new boolean[n]; queue = new int[n]; top = 0; // computes instruction indexes for (int i = 0; i < n; ++i) { indexes.put(m.instructions.get(i), i); } // computes exception handlers for each instruction for (int i = 0; i < m.tryCatchBlocks.size(); ++i) { TryCatchBlockNode tcb = (TryCatchBlockNode) m.tryCatchBlocks.get(i); int begin = indexes.get(tcb.start); int end = indexes.get(tcb.end); for (int j = begin; j < end; ++j) { List insnHandlers = handlers[j]; if (insnHandlers == null) { insnHandlers = new ArrayList(); handlers[j] = insnHandlers; } insnHandlers.add(tcb); } } // initializes the data structures for the control flow analysis algorithm Frame current = newFrame(m.maxLocals, m.maxStack); Frame handler = newFrame(m.maxLocals, m.maxStack); Type[] args = Type.getArgumentTypes(m.desc); int local = 0; if ((m.access & ACC_STATIC) == 0) { Type ctype = Type.getType("L" + c.name + ";"); current.setLocal(local++, interpreter.newValue(ctype)); } for (int i = 0; i < args.length; ++i) { current.setLocal(local++, interpreter.newValue(args[i])); if (args[i].getSize() == 2) { current.setLocal(local++, interpreter.newValue(null)); } } while (local < m.maxLocals) { current.setLocal(local++, interpreter.newValue(null)); } merge(0, current, null); // control flow analysis while (top > 0) { int insn = queue[--top]; Frame f = frames[insn]; Subroutine subroutine = subroutines[insn]; queued[insn] = false; try { Object o = m.instructions.get(insn); jsr = false; if (o instanceof Label) { merge(insn + 1, f, subroutine); } else { AbstractInsnNode insnNode = (AbstractInsnNode) o; int insnOpcode = insnNode.getOpcode(); current.init(f).execute(insnNode, interpreter); subroutine = subroutine == null ? null : subroutine.copy(); if (insnNode instanceof JumpInsnNode) { JumpInsnNode j = (JumpInsnNode) insnNode; if (insnOpcode != GOTO && insnOpcode != JSR) { merge(insn + 1, current, subroutine); } if (insnOpcode == JSR) { jsr = true; merge(indexes.get(j.label), current, new Subroutine(j.label, m.maxLocals, j)); } else { merge(indexes.get(j.label), current, subroutine); } } else if (insnNode instanceof LookupSwitchInsnNode) { LookupSwitchInsnNode lsi = (LookupSwitchInsnNode) insnNode; merge(indexes.get(lsi.dflt), current, subroutine); for (int j = 0; j < lsi.labels.size(); ++j) { Label label = (Label) lsi.labels.get(j); merge(indexes.get(label), current, subroutine); } } else if (insnNode instanceof TableSwitchInsnNode) { TableSwitchInsnNode tsi = (TableSwitchInsnNode) insnNode; merge(indexes.get(tsi.dflt), current, subroutine); for (int j = 0; j < tsi.labels.size(); ++j) { Label label = (Label) tsi.labels.get(j); merge(indexes.get(label), current, subroutine); } } else if (insnOpcode == RET) { if (subroutine == null) { throw new AnalyzerException("RET instruction outside of a sub routine"); } else { for (int i = 0; i < subroutine.callers.size(); ++i) { int caller = indexes.get(subroutine.callers.get(i)); merge(caller + 1, frames[caller], current, subroutines[caller], subroutine.access); } } } else if (insnOpcode != ATHROW && (insnOpcode < IRETURN || insnOpcode > RETURN)) { if (subroutine != null) { if (insnNode instanceof VarInsnNode) { int var = ((VarInsnNode) insnNode).var; subroutine.access[var] = true; if (insnOpcode == LLOAD || insnOpcode == DLOAD || insnOpcode == LSTORE || insnOpcode == DSTORE) { subroutine.access[var + 1] = true; } } else if (insnNode instanceof IincInsnNode) { int var = ((IincInsnNode) insnNode).var; subroutine.access[var] = true; } } merge(insn + 1, current, subroutine); } } List insnHandlers = handlers[insn]; if (insnHandlers != null) { for (int i = 0; i < insnHandlers.size(); ++i) { TryCatchBlockNode tcb = (TryCatchBlockNode) insnHandlers.get(i); Type type; if (tcb.type == null) { type = Type.getType("Ljava/lang/Throwable;"); } else { type = Type.getType("L" + tcb.type + ";"); } handler.init(f); handler.clearStack(); handler.push(interpreter.newValue(type)); merge(indexes.get(tcb.handler), handler, subroutine); } } } catch (Exception e) { throw new AnalyzerException("Error at instruction " + insn + ": " + e.getMessage()); } } return frames; }
public Value unaryOperation(final AbstractInsnNode insn, Value value) throws AnalyzerException { Value expected; switch (insn.getOpcode()) { case INEG: case IINC: case I2F: case I2L: case I2D: case I2B: case I2C: case I2S: case IFEQ: case IFNE: case IFLT: case IFGE: case IFGT: case IFLE: case TABLESWITCH: case LOOKUPSWITCH: case IRETURN: case NEWARRAY: case ANEWARRAY: expected = BasicValue.INT_VALUE; break; case FNEG: case F2I: case F2L: case F2D: case FRETURN: expected = BasicValue.FLOAT_VALUE; break; case LNEG: case L2I: case L2F: case L2D: case LRETURN: expected = BasicValue.LONG_VALUE; break; case DNEG: case D2I: case D2F: case D2L: case DRETURN: expected = BasicValue.DOUBLE_VALUE; break; case GETFIELD: expected = newValue(Type.getType("L" + ((FieldInsnNode) insn).owner + ";")); break; case CHECKCAST: if (!((BasicValue) value).isReference()) { throw new AnalyzerException(null, "an object reference", value); } return super.unaryOperation(insn, value); case ARRAYLENGTH: if (!isArrayValue(value)) { throw new AnalyzerException(null, "an array reference", value); } return super.unaryOperation(insn, value); case ARETURN: case ATHROW: case INSTANCEOF: case MONITORENTER: case MONITOREXIT: case IFNULL: case IFNONNULL: if (!((BasicValue) value).isReference()) { throw new AnalyzerException(null, "an object reference", value); } return super.unaryOperation(insn, value); case PUTSTATIC: expected = newValue(Type.getType(((FieldInsnNode) insn).desc)); break; default: throw new RuntimeException("Internal error."); } if (!isSubTypeOf(value, expected)) { throw new AnalyzerException(null, expected, value); } return super.unaryOperation(insn, value); }
public Value binaryOperation(final AbstractInsnNode insn, final Value value1, final Value value2) throws AnalyzerException { Value expected1; Value expected2; switch (insn.getOpcode()) { case IALOAD: case BALOAD: case CALOAD: case SALOAD: expected1 = newValue(Type.getType("[I")); expected2 = BasicValue.INT_VALUE; break; case LALOAD: expected1 = newValue(Type.getType("[J")); expected2 = BasicValue.INT_VALUE; break; case FALOAD: expected1 = newValue(Type.getType("[F")); expected2 = BasicValue.INT_VALUE; break; case DALOAD: expected1 = newValue(Type.getType("[D")); expected2 = BasicValue.INT_VALUE; break; case AALOAD: expected1 = newValue(Type.getType("[Ljava/lang/Object;")); expected2 = BasicValue.INT_VALUE; break; case IADD: case ISUB: case IMUL: case IDIV: case IREM: case ISHL: case ISHR: case IUSHR: case IAND: case IOR: case IXOR: case IF_ICMPEQ: case IF_ICMPNE: case IF_ICMPLT: case IF_ICMPGE: case IF_ICMPGT: case IF_ICMPLE: expected1 = BasicValue.INT_VALUE; expected2 = BasicValue.INT_VALUE; break; case FADD: case FSUB: case FMUL: case FDIV: case FREM: case FCMPL: case FCMPG: expected1 = BasicValue.FLOAT_VALUE; expected2 = BasicValue.FLOAT_VALUE; break; case LADD: case LSUB: case LMUL: case LDIV: case LREM: case LAND: case LOR: case LXOR: case LCMP: expected1 = BasicValue.LONG_VALUE; expected2 = BasicValue.LONG_VALUE; break; case LSHL: case LSHR: case LUSHR: expected1 = BasicValue.LONG_VALUE; expected2 = BasicValue.INT_VALUE; break; case DADD: case DSUB: case DMUL: case DDIV: case DREM: case DCMPL: case DCMPG: expected1 = BasicValue.DOUBLE_VALUE; expected2 = BasicValue.DOUBLE_VALUE; break; case IF_ACMPEQ: case IF_ACMPNE: expected1 = BasicValue.REFERENCE_VALUE; expected2 = BasicValue.REFERENCE_VALUE; break; case PUTFIELD: FieldInsnNode fin = (FieldInsnNode) insn; expected1 = newValue(Type.getType("L" + fin.owner + ";")); expected2 = newValue(Type.getType(fin.desc)); break; default: throw new RuntimeException("Internal error."); } if (!isSubTypeOf(value1, expected1)) { throw new AnalyzerException("First argument", expected1, value1); } else if (!isSubTypeOf(value2, expected2)) { throw new AnalyzerException("Second argument", expected2, value2); } if (insn.getOpcode() == AALOAD) { return getElementValue(value1); } else { return super.binaryOperation(insn, value1, value2); } }