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;
 }
Example #4
0
  /**
   * 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);
   }
 }