Esempio n. 1
0
  private void merge(
      final int insn,
      final Frame beforeJSR,
      final Frame afterRET,
      final Subroutine subroutineBeforeJSR,
      final boolean[] access)
      throws AnalyzerException {
    Frame oldFrame = frames[insn];
    Subroutine oldSubroutine = subroutines[insn];
    boolean changes;

    afterRET.merge(beforeJSR, access);

    if (oldFrame == null) {
      frames[insn] = newFrame(afterRET);
      changes = true;
    } else {
      changes = oldFrame.merge(afterRET, access);
    }

    if (oldSubroutine != null && subroutineBeforeJSR != null) {
      changes |= oldSubroutine.merge(subroutineBeforeJSR);
    }
    if (changes && !queued[insn]) {
      queued[insn] = true;
      queue[top++] = insn;
    }
  }
Esempio n. 2
0
  private void merge(final int insn, final Frame frame, final Subroutine subroutine)
      throws AnalyzerException {
    if (insn > n - 1) {
      throw new AnalyzerException("Execution can fall off end of the code");
    } else {
      Frame oldFrame = frames[insn];
      Subroutine oldSubroutine = subroutines[insn];
      boolean changes = false;

      if (oldFrame == null) {
        frames[insn] = newFrame(frame);
        changes = true;
      } else {
        changes |= oldFrame.merge(frame, interpreter);
      }

      newControlFlowEdge(frame, oldFrame);

      if (oldSubroutine == null) {
        if (subroutine != null) {
          subroutines[insn] = subroutine.copy();
          changes = true;
        }
      } else {
        if (subroutine != null) {
          changes |= oldSubroutine.merge(subroutine, !jsr);
        }
      }
      if (changes && !queued[insn]) {
        queued[insn] = true;
        queue[top++] = insn;
      }
    }
  }
Esempio n. 3
0
  private void merge(final int insn, final Frame frame, final Subroutine subroutine)
      throws AnalyzerException {
    Frame oldFrame = frames[insn];
    Subroutine oldSubroutine = subroutines[insn];
    boolean changes;

    if (oldFrame == null) {
      frames[insn] = newFrame(frame);
      changes = true;
    } else {
      changes = oldFrame.merge(frame, interpreter);
    }

    if (oldSubroutine == null) {
      if (subroutine != null) {
        subroutines[insn] = subroutine.copy();
        changes = true;
      }
    } else {
      if (subroutine != null) {
        changes |= oldSubroutine.merge(subroutine);
      }
    }
    if (changes && !queued[insn]) {
      queued[insn] = true;
      queue[top++] = insn;
    }
  }
Esempio n. 4
0
 public static LispObject evaluate(String name, Environment environment, List<LispObject> args) {
   for (Class c : getSubroutineContainers()) {
     for (Method m : c.getMethods()) {
       Subroutine annotation = m.getAnnotation(Subroutine.class);
       if (annotation == null || !annotation.value().equals(name)) continue;
       if (!Arrays.asList(mySpecialForms).contains(c)) {
         if (!environment.areArgumentsEvaluated()) {
           for (int i = 0, dataSize = args.size(); i < dataSize; i++) {
             args.set(i, args.get(i).evaluate(environment));
           }
         } else {
           environment.setArgumentsEvaluated(false);
         }
       }
       ArgumentsList arguments = parseArguments(m, environment, args);
       checkArguments(name, arguments, args);
       try {
         return (LispObject) m.invoke(null, arguments.getValues());
       } catch (IllegalAccessException | InvocationTargetException e) {
         if (e.getCause().getMessage() == null) e.getCause().printStackTrace();
         else System.err.println(e.getCause().getMessage());
         Throwable cause = getCause(e);
         if (cause instanceof LispThrow) throw (LispThrow) cause;
         if (cause instanceof VoidVariableException && TestMode.TEST && c == Key.class) {
           System.err.println("Skip keymap errors in test mode");
           return LispSymbol.ourNil;
         }
         if (cause instanceof LispException) throw (LispException) cause;
         cause.printStackTrace();
         throw new LispException(e.getCause().getMessage());
       }
     }
   }
   throw new InternalException(JelispBundle.message("unknown.subroutine", name));
 }
Esempio n. 5
0
 public Subroutine copy() {
   Subroutine result = new Subroutine();
   result.start = start;
   result.access = new boolean[access.length];
   System.arraycopy(access, 0, result.access, 0, access.length);
   result.callers = new ArrayList(callers);
   return result;
 }
Esempio n. 6
0
 /**
  * Returns the subroutine object associated with the given instruction. This is a costly
  * operation, you should consider using getSubroutine(InstructionHandle). Returns 'null' if the
  * given InstructionHandle lies in so-called 'dead code', i.e. code that can never be executed.
  *
  * @see #getSubroutine(InstructionHandle)
  * @see #getTopLevel()
  */
 public Subroutine subroutineOf(InstructionHandle any) {
   Iterator i = subroutines.values().iterator();
   while (i.hasNext()) {
     Subroutine s = (Subroutine) i.next();
     if (s.contains(any)) return s;
   }
   System.err.println("DEBUG: Please verify '" + any + "' lies in dead code.");
   return null;
   // throw new AssertionViolatedException("No subroutine for InstructionHandle found (DEAD
   // CODE?).");
 }
  private boolean scanOp(
      int pos, org.hotswap.agent.javassist.bytecode.CodeIterator iter, Subroutine sub)
      throws BadBytecode {
    subroutines[pos] = sub;

    int opcode = iter.byteAt(pos);

    if (opcode == TABLESWITCH) {
      scanTableSwitch(pos, iter, sub);

      return false;
    }

    if (opcode == LOOKUPSWITCH) {
      scanLookupSwitch(pos, iter, sub);

      return false;
    }

    // All forms of return and throw end current code flow
    if (Util.isReturn(opcode) || opcode == RET || opcode == ATHROW) {
      return false;
    }

    if (Util.isJumpInstruction(opcode)) {
      int target = Util.getJumpTarget(pos, iter);
      if (opcode == JSR || opcode == JSR_W) {
        Subroutine s = subTable.get(new Integer(target));
        if (s == null) {
          s = new Subroutine(target, pos);
          subTable.put(new Integer(target), s);
          scan(target, iter, s);
        } else {
          s.addCaller(pos);
        }
      } else {
        scan(target, iter, sub);

        // GOTO ends current code flow
        if (Util.isGoto(opcode)) {
          return false;
        }
      }
    }

    return true;
  }
Esempio n. 8
0
  private void merge(
      final int insn,
      final Frame beforeJSR,
      final Frame afterRET,
      final Subroutine subroutineBeforeJSR,
      final boolean[] access)
      throws AnalyzerException {
    if (insn > n - 1) {
      throw new AnalyzerException("Execution can fall off end of the code");
    } else {
      Frame oldFrame = frames[insn];
      Subroutine oldSubroutine = subroutines[insn];
      boolean changes = false;

      afterRET.merge(beforeJSR, access);

      if (oldFrame == null) {
        frames[insn] = newFrame(afterRET);
        changes = true;
      } else {
        changes |= oldFrame.merge(afterRET, access);
      }

      newControlFlowEdge(afterRET, oldFrame);

      if (oldSubroutine == null) {
        if (subroutineBeforeJSR != null) {
          subroutines[insn] = subroutineBeforeJSR.copy();
          changes = true;
        }
      } else {
        if (subroutineBeforeJSR != null) {
          changes |= oldSubroutine.merge(subroutineBeforeJSR, !jsr);
        }
      }
      if (changes && !queued[insn]) {
        queued[insn] = true;
        queue[top++] = insn;
      }
    }
  }
Esempio n. 9
0
  @Override
  public void analyze(Log log, SymbolTable outer, Subroutine owner, boolean inLoop) {

    List<Subroutine> subroutines = getSubroutines();

    // Create the table if it hasn't already been created.  For blocks that are bodies of
    // functions or loops, the analyze() method of the function or loop will have created this
    // table already, since it is the table in which the parameters or loop indices belong.
    // For blocks that are entire scripts, the table will have already been created, too.
    // All other blocks will need their tables created here.
    if (table == null) {
      table = new SymbolTable(outer);
    }

    // Insert the routines into the table, but analyze ONLY the parameters and return types.
    // We can't analyze the function bodies until all the functions have been put into the
    // table (with analyzed parameters) because within any function body there can be a call
    // to any other function, and we have to be able to analyze the call.  Notice also that the
    // functions are going in before any variables are being looked at since variables can call
    // any function in their initializing expressions.
    for (Subroutine subroutine : subroutines) {
      subroutine.analyzeSignature(log, table, owner, inLoop);
      table.insert(subroutine, log);
    }

    // Now just go through all the items in order and analyze everything, making sure to
    // insert variables because they have not yet been inserted.
    for (Statement s : statements) {
      if (s instanceof DecStatement) {
        DecStatement d = (DecStatement) s;
        for (String t : d.getNames()) {
          table.insert(new Variable(t), log);
        }
      }
      s.analyze(log, table, owner, inLoop);
    }
  }
Esempio n. 10
0
  /**
   * This (recursive) utility method makes sure that 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.
   *
   * @throws StructuralCodeConstraintException if the above constraint is not satisfied.
   */
  private void noRecursiveCalls(Subroutine sub, HashSet<Integer> set) {
    Subroutine[] subs = sub.subSubs();

    for (int i = 0; i < subs.length; i++) {
      int index = ((RET) (subs[i].getLeavingRET().getInstruction())).getIndex();

      if (!set.add(new Integer(index))) {
        // Don't use toString() here because of possibly infinite recursive subSubs() calls then.
        SubroutineImpl si = (SubroutineImpl) subs[i];
        throw new StructuralCodeConstraintException(
            "Subroutine with local variable '"
                + si.localVariable
                + "', JSRs '"
                + si.theJSRs
                + "', RET '"
                + si.theRET
                + "' is called by a subroutine which uses the same local variable index as itself; maybe even a recursive call? JustIce's clean definition of a subroutine forbids both.");
      }

      noRecursiveCalls(subs[i], set);

      set.remove(new Integer(index));
    }
  }
Esempio n. 11
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;
  }
Esempio n. 12
0
  /**
   * 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>());
  }
Esempio n. 13
0
  /**
   * Analyzes the given method.
   *
   * @param owner the internal name of 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 String owner, final MethodNode m) throws AnalyzerException {
    if ((m.access & (ACC_ABSTRACT | ACC_NATIVE)) != 0) {
      frames = new Frame[0];
      return frames;
    }
    n = m.instructions.size();
    insns = m.instructions;
    handlers = new List[n];
    frames = new Frame[n];
    subroutines = new Subroutine[n];
    queued = new boolean[n];
    queue = new int[n];
    top = 0;

    // computes exception handlers for each instruction
    for (int i = 0; i < m.tryCatchBlocks.size(); ++i) {
      TryCatchBlockNode tcb = (TryCatchBlockNode) m.tryCatchBlocks.get(i);
      int begin = insns.indexOf(tcb.start);
      int end = insns.indexOf(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);
      }
    }

    // computes the subroutine for each instruction:
    Subroutine main = new Subroutine(null, m.maxLocals, null);
    List subroutineCalls = new ArrayList();
    Map subroutineHeads = new HashMap();
    findSubroutine(0, main, subroutineCalls);
    while (!subroutineCalls.isEmpty()) {
      JumpInsnNode jsr = (JumpInsnNode) subroutineCalls.remove(0);
      Subroutine sub = (Subroutine) subroutineHeads.get(jsr.label);
      if (sub == null) {
        sub = new Subroutine(jsr.label, m.maxLocals, jsr);
        subroutineHeads.put(jsr.label, sub);
        findSubroutine(insns.indexOf(jsr.label), sub, subroutineCalls);
      } else {
        sub.callers.add(jsr);
      }
    }
    for (int i = 0; i < n; ++i) {
      if (subroutines[i] != null && subroutines[i].start == null) {
        subroutines[i] = null;
      }
    }

    // initializes the data structures for the control flow analysis
    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.getObjectType(owner);
      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 {
        AbstractInsnNode insnNode = m.instructions.get(insn);
        int insnOpcode = insnNode.getOpcode();
        int insnType = insnNode.getType();

        if (insnType == AbstractInsnNode.LABEL
            || insnType == AbstractInsnNode.LINE
            || insnType == AbstractInsnNode.FRAME) {
          merge(insn + 1, f, subroutine);
          newControlFlowEdge(insn, insn + 1);
        } else {
          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);
              newControlFlowEdge(insn, insn + 1);
            }
            int jump = insns.indexOf(j.label);
            if (insnOpcode == JSR) {
              merge(jump, current, new Subroutine(j.label, m.maxLocals, j));
            } else {
              merge(jump, current, subroutine);
            }
            newControlFlowEdge(insn, jump);
          } else if (insnNode instanceof LookupSwitchInsnNode) {
            LookupSwitchInsnNode lsi = (LookupSwitchInsnNode) insnNode;
            int jump = insns.indexOf(lsi.dflt);
            merge(jump, current, subroutine);
            newControlFlowEdge(insn, jump);
            for (int j = 0; j < lsi.labels.size(); ++j) {
              LabelNode label = (LabelNode) lsi.labels.get(j);
              jump = insns.indexOf(label);
              merge(jump, current, subroutine);
              newControlFlowEdge(insn, jump);
            }
          } else if (insnNode instanceof TableSwitchInsnNode) {
            TableSwitchInsnNode tsi = (TableSwitchInsnNode) insnNode;
            int jump = insns.indexOf(tsi.dflt);
            merge(jump, current, subroutine);
            newControlFlowEdge(insn, jump);
            for (int j = 0; j < tsi.labels.size(); ++j) {
              LabelNode label = (LabelNode) tsi.labels.get(j);
              jump = insns.indexOf(label);
              merge(jump, current, subroutine);
              newControlFlowEdge(insn, jump);
            }
          } else if (insnOpcode == RET) {
            if (subroutine == null) {
              throw new AnalyzerException("RET instruction outside of a sub routine");
            }
            for (int i = 0; i < subroutine.callers.size(); ++i) {
              Object caller = subroutine.callers.get(i);
              int call = insns.indexOf((AbstractInsnNode) caller);
              if (frames[call] != null) {
                merge(call + 1, frames[call], current, subroutines[call], subroutine.access);
                newControlFlowEdge(insn, call + 1);
              }
            }
          } 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);
            newControlFlowEdge(insn, insn + 1);
          }
        }

        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.getObjectType("java/lang/Throwable");
            } else {
              type = Type.getObjectType(tcb.type);
            }
            int jump = insns.indexOf(tcb.handler);
            if (newControlFlowExceptionEdge(insn, jump)) {
              handler.init(f);
              handler.clearStack();
              handler.push(interpreter.newValue(type));
              merge(jump, handler, subroutine);
            }
          }
        }
      } catch (AnalyzerException e) {
        throw new AnalyzerException("Error at instruction " + insn + ": " + e.getMessage(), e);
      } catch (Exception e) {
        throw new AnalyzerException("Error at instruction " + insn + ": " + e.getMessage(), e);
      }
    }

    return frames;
  }
Esempio n. 14
0
  private void findSubroutine(int insn, final Subroutine sub, final List calls)
      throws AnalyzerException {
    while (true) {
      if (insn < 0 || insn >= n) {
        throw new AnalyzerException("Execution can fall off end of the code");
      }
      if (subroutines[insn] != null) {
        return;
      }
      subroutines[insn] = sub.copy();
      AbstractInsnNode node = insns.get(insn);

      // calls findSubroutine recursively on normal successors
      if (node instanceof JumpInsnNode) {
        if (node.getOpcode() == JSR) {
          // do not follow a JSR, it leads to another subroutine!
          calls.add(node);
        } else {
          JumpInsnNode jnode = (JumpInsnNode) node;
          findSubroutine(insns.indexOf(jnode.label), sub, calls);
        }
      } else if (node instanceof TableSwitchInsnNode) {
        TableSwitchInsnNode tsnode = (TableSwitchInsnNode) node;
        findSubroutine(insns.indexOf(tsnode.dflt), sub, calls);
        for (int i = tsnode.labels.size() - 1; i >= 0; --i) {
          LabelNode l = (LabelNode) tsnode.labels.get(i);
          findSubroutine(insns.indexOf(l), sub, calls);
        }
      } else if (node instanceof LookupSwitchInsnNode) {
        LookupSwitchInsnNode lsnode = (LookupSwitchInsnNode) node;
        findSubroutine(insns.indexOf(lsnode.dflt), sub, calls);
        for (int i = lsnode.labels.size() - 1; i >= 0; --i) {
          LabelNode l = (LabelNode) lsnode.labels.get(i);
          findSubroutine(insns.indexOf(l), sub, calls);
        }
      }

      // calls findSubroutine recursively on exception handler successors
      List insnHandlers = handlers[insn];
      if (insnHandlers != null) {
        for (int i = 0; i < insnHandlers.size(); ++i) {
          TryCatchBlockNode tcb = (TryCatchBlockNode) insnHandlers.get(i);
          findSubroutine(insns.indexOf(tcb.handler), sub, calls);
        }
      }

      // if insn does not falls through to the next instruction, return.
      switch (node.getOpcode()) {
        case GOTO:
        case RET:
        case TABLESWITCH:
        case LOOKUPSWITCH:
        case IRETURN:
        case LRETURN:
        case FRETURN:
        case DRETURN:
        case ARETURN:
        case RETURN:
        case ATHROW:
          return;
      }
      insn++;
    }
  }