Exemple #1
0
 /**
  * Sets the leaving RET instruction. Must be invoked after all instructions are added. Must not
  * be invoked for top-level 'subroutine'.
  */
 void setLeavingRET() {
   if (localVariable == UNSET) {
     throw new AssertionViolatedException(
         "setLeavingRET() called for top-level 'subroutine' or forgot to set local variable first.");
   }
   Iterator iter = instructions.iterator();
   InstructionHandle ret = null;
   while (iter.hasNext()) {
     InstructionHandle actual = (InstructionHandle) iter.next();
     if (actual.getInstruction() instanceof RET) {
       if (ret != null) {
         throw new StructuralCodeConstraintException(
             "Subroutine with more then one RET detected: '" + ret + "' and '" + actual + "'.");
       } else {
         ret = actual;
       }
     }
   }
   if (ret == null) {
     throw new StructuralCodeConstraintException("Subroutine without a RET detected.");
   }
   if (((RET) ret.getInstruction()).getIndex() != localVariable) {
     throw new StructuralCodeConstraintException(
         "Subroutine uses '"
             + ret
             + "' which does not match the correct local variable '"
             + localVariable
             + "'.");
   }
   theRET = ret;
 }
Exemple #2
0
  /**
   * A utility method that calculates the successors of a given InstructionHandle <B>in the same
   * subroutine</B>. That means, a RET does not have any successors as defined here. A
   * JsrInstruction has its physical successor as its successor (opposed to its target) as defined
   * here.
   */
  private static InstructionHandle[] getSuccessors(InstructionHandle instruction) {
    final InstructionHandle[] empty = new InstructionHandle[0];
    final InstructionHandle[] single = new InstructionHandle[1];
    final InstructionHandle[] pair = new InstructionHandle[2];

    Instruction inst = instruction.getInstruction();

    if (inst instanceof RET) {
      return empty;
    }

    // Terminates method normally.
    if (inst instanceof ReturnInstruction) {
      return empty;
    }

    // Terminates method abnormally, because JustIce mandates
    // subroutines not to be protected by exception handlers.
    if (inst instanceof ATHROW) {
      return empty;
    }

    // See method comment.
    if (inst instanceof JsrInstruction) {
      single[0] = instruction.getNext();
      return single;
    }

    if (inst instanceof GotoInstruction) {
      single[0] = ((GotoInstruction) inst).getTarget();
      return single;
    }

    if (inst instanceof BranchInstruction) {
      if (inst instanceof Select) {
        // BCEL's getTargets() returns only the non-default targets,
        // thanks to Eli Tilevich for reporting.
        InstructionHandle[] matchTargets = ((Select) inst).getTargets();
        InstructionHandle[] ret = new InstructionHandle[matchTargets.length + 1];
        ret[0] = ((Select) inst).getTarget();
        System.arraycopy(matchTargets, 0, ret, 1, matchTargets.length);
        return ret;
      } else {
        pair[0] = instruction.getNext();
        pair[1] = ((BranchInstruction) inst).getTarget();
        return pair;
      }
    }

    // default case: Fall through.
    single[0] = instruction.getNext();
    return single;
  }
Exemple #3
0
 /** Adds a new JSR or JSR_W that has this subroutine as its target. */
 public void addEnteringJsrInstruction(InstructionHandle jsrInst) {
   if ((jsrInst == null) || (!(jsrInst.getInstruction() instanceof JsrInstruction))) {
     throw new AssertionViolatedException("Expecting JsrInstruction InstructionHandle.");
   }
   if (localVariable == UNSET) {
     throw new AssertionViolatedException("Set the localVariable first!");
   } else {
     // Something is wrong when an ASTORE is targeted that does not operate on the same local
     // variable than the rest of the
     // JsrInstruction-targets and the RET.
     // (We don't know out leader here so we cannot check if we're really targeted!)
     if (localVariable
         != ((ASTORE) (((JsrInstruction) jsrInst.getInstruction()).getTarget().getInstruction()))
             .getIndex()) {
       throw new AssertionViolatedException("Setting a wrong JsrInstruction.");
     }
   }
   theJSRs.add(jsrInst);
 }
Exemple #4
0
    /*
     * Satisfies Subroutine.getAccessedLocalIndices().
     */
    public int[] getAccessedLocalsIndices() {
      // TODO: Implement caching.
      HashSet<Integer> acc = new HashSet<Integer>();
      if (theRET == null && this != TOPLEVEL) {
        throw new AssertionViolatedException(
            "This subroutine object must be built up completely before calculating accessed locals.");
      }
      Iterator i = instructions.iterator();
      while (i.hasNext()) {
        InstructionHandle ih = (InstructionHandle) i.next();
        // RET is not a LocalVariableInstruction in the current version of BCEL.
        if (ih.getInstruction() instanceof LocalVariableInstruction
            || ih.getInstruction() instanceof RET) {
          int idx = ((IndexedInstruction) (ih.getInstruction())).getIndex();
          acc.add(new Integer(idx));
          // LONG? DOUBLE?.
          try {
            // LocalVariableInstruction instances are typed without the need to look into
            // the constant pool.
            if (ih.getInstruction() instanceof LocalVariableInstruction) {
              int s = ((LocalVariableInstruction) ih.getInstruction()).getType(null).getSize();
              if (s == 2) acc.add(new Integer(idx + 1));
            }
          } catch (RuntimeException re) {
            throw new AssertionViolatedException(
                "Oops. BCEL did not like NULL as a ConstantPoolGen object.");
          }
        }
      }

      int[] ret = new int[acc.size()];
      i = acc.iterator();
      int j = -1;
      while (i.hasNext()) {
        j++;
        ret[j] = ((Integer) i.next()).intValue();
      }
      return ret;
    }
Exemple #5
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>());
  }