Pass1Verifier.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  *  Unless required by applicable law or agreed to in writing, software
  12.  *  distributed under the License is distributed on an "AS IS" BASIS,
  13.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  *  See the License for the specific language governing permissions and
  15.  *  limitations under the License.
  16.  */
  17. package org.apache.bcel.verifier.statics;

  18. import org.apache.bcel.Repository;
  19. import org.apache.bcel.classfile.ClassFormatException;
  20. import org.apache.bcel.classfile.JavaClass;
  21. import org.apache.bcel.verifier.PassVerifier;
  22. import org.apache.bcel.verifier.VerificationResult;
  23. import org.apache.bcel.verifier.Verifier;
  24. import org.apache.bcel.verifier.exc.LoadingException;
  25. import org.apache.commons.lang3.ArrayUtils;

  26. /**
  27.  * This PassVerifier verifies a class file according to pass 1 as described in The Java Virtual Machine Specification,
  28.  * 2nd edition. More detailed information is to be found at the do_verify() method's documentation.
  29.  *
  30.  * @see #do_verify()
  31.  */
  32. public final class Pass1Verifier extends PassVerifier {
  33.     /**
  34.      * DON'T USE THIS EVEN PRIVATELY! USE getJavaClass() INSTEAD.
  35.      *
  36.      * @see #getJavaClass()
  37.      */
  38.     private JavaClass javaClass;

  39.     /**
  40.      * The Verifier that created this.
  41.      */
  42.     private final Verifier verifier;

  43.     /**
  44.      * Should only be instantiated by a Verifier.
  45.      *
  46.      * @see Verifier
  47.      */
  48.     public Pass1Verifier(final Verifier verifier) {
  49.         this.verifier = verifier;
  50.     }

  51.     /**
  52.      * Pass-one verification basically means loading in a class file. The Java Virtual Machine Specification is not too
  53.      * precise about what makes the difference between passes one and two. The answer is that only pass one is performed on
  54.      * a class file as long as its resolution is not requested; whereas pass two and pass three are performed during the
  55.      * resolution process. Only four constraints to be checked are explicitly stated by The Java Virtual Machine
  56.      * Specification, 2nd edition:
  57.      * <UL>
  58.      * <LI>The first four bytes must contain the right magic number (0xCAFEBABE).
  59.      * <LI>All recognized attributes must be of the proper length.
  60.      * <LI>The class file must not be truncated or have extra bytes at the end.
  61.      * <LI>The constant pool must not contain any superficially unrecognizable information.
  62.      * </UL>
  63.      * A more in-depth documentation of what pass one should do was written by <A HREF=mailto:pwfong@cs.sfu.ca>Philip W. L.
  64.      * Fong</A>:
  65.      * <UL>
  66.      * <LI>the file should not be truncated.
  67.      * <LI>the file should not have extra bytes at the end.
  68.      * <LI>all variable-length structures should be well-formatted:
  69.      * <UL>
  70.      * <LI>there should only be constant_pool_count-1 many entries in the constant pool.
  71.      * <LI>all constant pool entries should have size the same as indicated by their type tag.
  72.      * <LI>there are exactly interfaces_count many entries in the interfaces array of the class file.
  73.      * <LI>there are exactly fields_count many entries in the fields array of the class file.
  74.      * <LI>there are exactly methods_count many entries in the methods array of the class file.
  75.      * <LI>there are exactly attributes_count many entries in the attributes array of the class file, fields, methods, and
  76.      * code attribute.
  77.      * <LI>there should be exactly attribute_length many bytes in each attribute. Inconsistency between attribute_length and
  78.      * the actually size of the attribute content should be uncovered. For example, in an Exceptions attribute, the actual
  79.      * number of exceptions as required by the number_of_exceptions field might yeild an attribute size that doesn't match
  80.      * the attribute_length. Such an anomaly should be detected.
  81.      * <LI>all attributes should have proper length. In particular, under certain context (e.g. while parsing method_info),
  82.      * recognizable attributes (e.g. "Code" attribute) should have correct format (e.g. attribute_length is 2).
  83.      * </UL>
  84.      * <LI>Also, certain constant values are checked for validity:
  85.      * <UL>
  86.      * <LI>The magic number should be 0xCAFEBABE.
  87.      * <LI>The major and minor version numbers are valid.
  88.      * <LI>All the constant pool type tags are recognizable.
  89.      * <LI>All undocumented access flags are masked off before use. Strictly speaking, this is not really a check.
  90.      * <LI>The field this_class should point to a string that represents a legal non-array class name, and this name should
  91.      * be the same as the class file being loaded.
  92.      * <LI>the field super_class should point to a string that represents a legal non-array class name.
  93.      * <LI>Because some of the above checks require cross referencing the constant pool entries, guards are set up to make
  94.      * sure that the referenced entries are of the right type and the indices are within the legal range (0 &lt; index &lt;
  95.      * constant_pool_count).
  96.      * </UL>
  97.      * <LI>Extra checks done in pass 1:
  98.      * <UL>
  99.      * <LI>the constant values of static fields should have the same type as the fields.
  100.      * <LI>the number of words in a parameter list does not exceed 255 and locals_max.
  101.      * <LI>the name and signature of fields and methods are verified to be of legal format.
  102.      * </UL>
  103.      * </UL>
  104.      * (From the Paper <A HREF="http://www.cs.sfu.ca/people/GradStudents/pwfong/personal/JVM/pass1/"> The Mysterious Pass
  105.      * One, first draft, September 2, 1997</A>.)
  106.      *
  107.      * <P>
  108.      * However, most of this is done by parsing a class file or generating a class file into BCEL's internal data structure.
  109.      * <B>Therefore, all that is really done here is look up the class file from BCEL's repository.</B> This is also
  110.      * motivated by the fact that some omitted things (like the check for extra bytes at the end of the class file) are
  111.      * handy when actually using BCEL to repair a class file (otherwise you would not be able to load it into BCEL).
  112.      * </P>
  113.      *
  114.      * @see org.apache.bcel.Repository
  115.      * @see org.apache.bcel.Const#JVM_CLASSFILE_MAGIC
  116.      */
  117.     @Override
  118.     public VerificationResult do_verify() {
  119.         JavaClass jc;
  120.         try {
  121.             jc = getJavaClass(); // loads in the class file if not already done.

  122.             /* If we find more constraints to check, we should do this in an own method. */
  123.             // This should maybe caught by BCEL: In case of renamed .class files we get wrong
  124.             // JavaClass objects here.
  125.             // This test should be much more complicated. It needs to take the class name, remove any portion at the
  126.             // end that matches the file name and then see if the remainder matches anything on the class path.
  127.             // Dumb test for now, see if the class name ends with the file name.
  128.             if (jc != null && !verifier.getClassName().equals(jc.getClassName()) && !jc.getClassName().endsWith(verifier.getClassName())) {
  129.                 throw new LoadingException("Wrong name: the internal name of the .class file '" + jc.getClassName() + "' does not match the file's name '"
  130.                     + verifier.getClassName() + "'.");
  131.             }
  132.         } catch (final LoadingException | ClassFormatException e) {
  133.             return new VerificationResult(VerificationResult.VERIFIED_REJECTED, e.getMessage());
  134.         } catch (final RuntimeException e) {
  135.             // BCEL does not catch every possible RuntimeException; e.g. if
  136.             // a constant pool index is referenced that does not exist.
  137.             return new VerificationResult(VerificationResult.VERIFIED_REJECTED, "Parsing via BCEL did not succeed. " + " exception occurred:\n" + e.toString());
  138.             // Don't think we want to dump a stack trace unless we have some sort of a debug option.
  139.             // e.getClass().getName()+" occurred:\n"+Utility.getStackTrace(e));
  140.         }

  141.         if (jc != null) {
  142.             return VerificationResult.VR_OK;
  143.         }
  144.         // TODO: Maybe change Repository's behavior to throw a LoadingException instead of just returning "null"
  145.         // if a class file cannot be found or in another way be looked up.
  146.         return new VerificationResult(VerificationResult.VERIFIED_REJECTED, "Repository.lookup() failed. FILE NOT FOUND?");
  147.     }

  148.     /**
  149.      * Used to load in and return the myOwner-matching JavaClass object when needed. Avoids loading in a class file when
  150.      * it's not really needed!
  151.      */
  152.     private JavaClass getJavaClass() {
  153.         if (javaClass == null) {
  154.             try {
  155.                 javaClass = Repository.lookupClass(verifier.getClassName());
  156.             } catch (final ClassNotFoundException ignored) {
  157.                 // FIXME: currently, Pass1Verifier treats jc == null as a special
  158.                 // case, so we don't need to do anything here. A better solution
  159.                 // would be to simply throw the ClassNotFoundException
  160.                 // out of this method.
  161.             }
  162.         }
  163.         return javaClass;
  164.     }

  165.     /**
  166.      * Currently this returns an empty array of String. One could parse the error messages of BCEL (written to
  167.      * java.lang.System.err) when loading a class file such as detecting unknown attributes or trailing garbage at the end
  168.      * of a class file. However, Markus Dahm does not like the idea so this method is currently useless and therefore marked
  169.      * as <b>TODO</b>.
  170.      */
  171.     @Override
  172.     public String[] getMessages() {
  173.         return ArrayUtils.EMPTY_STRING_ARRAY;
  174.     }

  175. }