예제 #1
0
  /**
   * Pass-one verification basically means loading in a class file. The Java Virtual Machine
   * Specification is not too precise about what makes the difference between passes one and two.
   * The answer is that only pass one is performed on a class file as long as its resolution is not
   * requested; whereas pass two and pass three are performed during the resolution process. Only
   * four constraints to be checked are explicitely stated by The Java Virtual Machine
   * Specification, 2nd edition:
   *
   * <UL>
   *   <LI>The first four bytes must contain the right magic number (0xCAFEBABE).
   *   <LI>All recognized attributes must be of the proper length.
   *   <LI>The class file must not be truncated or have extra bytes at the end.
   *   <LI>The constant pool must not contain any superficially unrecognizable information.
   * </UL>
   *
   * A more in-depth documentation of what pass one should do was written by <A
   * HREF=mailto:[email protected]>Philip W. L. Fong</A>:
   *
   * <UL>
   *   <LI>the file should not be truncated.
   *   <LI>the file should not have extra bytes at the end.
   *   <LI>all variable-length structures should be well-formatted:
   *       <UL>
   *         <LI>there should only be constant_pool_count-1 many entries in the constant pool.
   *         <LI>all constant pool entries should have size the same as indicated by their type tag.
   *         <LI>there are exactly interfaces_count many entries in the interfaces array of the
   *             class file.
   *         <LI>there are exactly fields_count many entries in the fields array of the class file.
   *         <LI>there are exactly methods_count many entries in the methods array of the class
   *             file.
   *         <LI>there are exactly attributes_count many entries in the attributes array of the
   *             class file, fields, methods, and code attribute.
   *         <LI>there should be exactly attribute_length many bytes in each attribute.
   *             Inconsistency between attribute_length and the actually size of the attribute
   *             content should be uncovered. For example, in an Exceptions attribute, the actual
   *             number of exceptions as required by the number_of_exceptions field might yeild an
   *             attribute size that doesn't match the attribute_length. Such an anomaly should be
   *             detected.
   *         <LI>all attributes should have proper length. In particular, under certain context
   *             (e.g. while parsing method_info), recognizable attributes (e.g. "Code" attribute)
   *             should have correct format (e.g. attribute_length is 2).
   *       </UL>
   *   <LI>Also, certain constant values are checked for validity:
   *       <UL>
   *         <LI>The magic number should be 0xCAFEBABE.
   *         <LI>The major and minor version numbers are valid.
   *         <LI>All the constant pool type tags are recognizable.
   *         <LI>All undocumented access flags are masked off before use. Strictly speaking, this is
   *             not really a check.
   *         <LI>The field this_class should point to a string that represents a legal non-array
   *             class name, and this name should be the same as the class file being loaded.
   *         <LI>the field super_class should point to a string that represents a legal non-array
   *             class name.
   *         <LI>Because some of the above checks require cross referencing the constant pool
   *             entries, guards are set up to make sure that the referenced entries are of the
   *             right type and the indices are within the legal range (0 < index <
   *             constant_pool_count).
   *       </UL>
   *   <LI>Extra checks done in pass 1:
   *       <UL>
   *         <LI>the constant values of static fields should have the same type as the fields.
   *         <LI>the number of words in a parameter list does not exceed 255 and locals_max.
   *         <LI>the name and signature of fields and methods are verified to be of legal format.
   *       </UL>
   * </UL>
   *
   * (From the Paper <A HREF=http://www.cs.sfu.ca/people/GradStudents/pwfong/personal/JVM/pass1/>The
   * Mysterious Pass One, first draft, September 2, 1997</A>.) </BR> However, most of this is done
   * by parsing a class file or generating a class file into BCEL's internal data structure.
   * <B>Therefore, all that is really done here is look up the class file from BCEL's
   * repository.</B> This is also motivated by the fact that some omitted things (like the check for
   * extra bytes at the end of the class file) are handy when actually using BCEL to repair a class
   * file (otherwise you would not be able to load it into BCEL).
   *
   * @see org.aspectj.apache.bcel.Repository
   */
  public VerificationResult do_verify() {
    JavaClass jc;
    try {
      jc = getJavaClass(); // loads in the class file if not already done.

      if (jc != null) {
        /* If we find more constraints to check, we should do this in an own method. */
        if (!myOwner.getClassName().equals(jc.getClassName())) {
          // This should maybe caught by BCEL: In case of renamed .class files we get wrong
          // JavaClass objects here.
          throw new LoadingException(
              "Wrong name: the internal name of the .class file '"
                  + jc.getClassName()
                  + "' does not match the file's name '"
                  + myOwner.getClassName()
                  + "'.");
        }
      }

    } catch (LoadingException e) {
      return new VerificationResult(VerificationResult.VERIFIED_REJECTED, e.getMessage());
    } catch (ClassFormatError e) {
      // BCEL sometimes is a little harsh describing exceptual situations.
      return new VerificationResult(VerificationResult.VERIFIED_REJECTED, e.getMessage());
    } catch (RuntimeException e) {
      // BCEL does not catch every possible RuntimeException; e.g. if
      // a constant pool index is referenced that does not exist.
      return new VerificationResult(
          VerificationResult.VERIFIED_REJECTED,
          "Parsing via BCEL did not succeed. "
              + e.getClass().getName()
              + " occured:\n"
              + Utility.getStackTrace(e));
    }

    if (jc != null) {
      return VerificationResult.VR_OK;
    } else {
      // TODO: Maybe change Repository's behaviour to throw a LoadingException instead of just
      // returning "null"
      //      if a class file cannot be found or in another way be looked up.
      return new VerificationResult(
          VerificationResult.VERIFIED_REJECTED, "Repository.lookup() failed. FILE NOT FOUND?");
    }
  }
예제 #2
0
  /**
   * 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.aspectj.apache.bcel.verifier.statics.LocalVariablesInfo
   * @see org.aspectj.apache.bcel.verifier.statics.Pass2Verifier#getLocalVariablesInfo(int)
   */
  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 = Repository.lookupClass(myOwner.getClassName());

    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(new ObjectType(jc.getClassName()));
            f.getLocals().set(0, Frame._this);
          } else {
            Frame._this = null;
            f.getLocals().set(0, new ObjectType(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(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");
    }
    return VerificationResult.VR_OK;
  }
예제 #3
0
 /**
  * Used to load in and return the myOwner-matching JavaClass object when needed. Avoids loading in
  * a class file when it's not really needed!
  */
 private JavaClass getJavaClass() {
   if (jc == null) {
     jc = Repository.lookupClass(myOwner.getClassName());
   }
   return jc;
 }