    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 *  Unless required by applicable law or agreed to in writing, software
    012 *  distributed under the License is distributed on an "AS IS" BASIS,
    013 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 *  See the License for the specific language governing permissions and
    015 *  limitations under the License.
    016 *
    017 */
    018package org.apache.bcel.verifier.statics;
    019
    020
    021import org.apache.bcel.Repository;
    022import org.apache.bcel.classfile.ClassFormatException;
    023import org.apache.bcel.classfile.JavaClass;
    024import org.apache.bcel.verifier.PassVerifier;
    025import org.apache.bcel.verifier.VerificationResult;
    026import org.apache.bcel.verifier.Verifier;
    027import org.apache.bcel.verifier.exc.LoadingException;
    028import org.apache.bcel.verifier.exc.Utility;
    029
    030/**
    031 * This PassVerifier verifies a class file according to pass 1 as
    032 * described in The Java Virtual Machine Specification, 2nd edition.
    033 * More detailed information is to be found at the do_verify() method's
    034 * documentation.
    035 *
    036 * @version $Id: Pass1Verifier.java 1806200 2017-08-25 16:33:06Z ggregory $
    037 * @see #do_verify()
    038 */
    039public final class Pass1Verifier extends PassVerifier{
    040    /**
    041     * DON'T USE THIS EVEN PRIVATELY! USE getJavaClass() INSTEAD.
    042     * @see #getJavaClass()
    043     */
    044    private JavaClass jc;
    045
    046    /**
    047     * The Verifier that created this.
    048     */
    049    private final Verifier myOwner;
    050
    051    /**
    052     * Used to load in and return the myOwner-matching JavaClass object when needed.
    053     * Avoids loading in a class file when it's not really needed!
    054     */
    055    private JavaClass getJavaClass() {
    056        if (jc == null) {
    057            try {
    058                jc = Repository.lookupClass(myOwner.getClassName());
    059            } catch (final ClassNotFoundException e) {
    060                // FIXME: currently, Pass1Verifier treats jc == null as a special
    061                // case, so we don't need to do anything here.  A better solution
    062                // would be to simply throw the ClassNotFoundException
    063                // out of this method.
    064            }
    065        }
    066        return jc;
    067    }
    068
    069    /**
    070     * Should only be instantiated by a Verifier.
    071     *
    072     * @see Verifier
    073     */
    074    public Pass1Verifier(final Verifier owner) {
    075        myOwner = owner;
    076    }
    077
    078    /**
    079     * Pass-one verification basically means loading in a class file.
    080     * The Java Virtual Machine Specification is not too precise about
    081     * what makes the difference between passes one and two.
    082     * The answer is that only pass one is performed on a class file as
    083     * long as its resolution is not requested; whereas pass two and
    084     * pass three are performed during the resolution process.
    085     * Only four constraints to be checked are explicitly stated by
    086     * The Java Virtual Machine Specification, 2nd edition:
    087     * <UL>
    088     *  <LI>The first four bytes must contain the right magic number (0xCAFEBABE).
    089     *  <LI>All recognized attributes must be of the proper length.
    090     *  <LI>The class file must not be truncated or have extra bytes at the end.
    091     *  <LI>The constant pool must not contain any superficially unrecognizable information.
    092     * </UL>
    093     * A more in-depth documentation of what pass one should do was written by
    094     * <A HREF=mailto:pwfong@cs.sfu.ca>Philip W. L. Fong</A>:
    095     * <UL>
    096     *  <LI> the file should not be truncated.
    097     *  <LI> the file should not have extra bytes at the end.
    098     *  <LI> all variable-length structures should be well-formatted:
    099     *  <UL>
    100     *   <LI> there should only be constant_pool_count-1 many entries in the constant pool.
    101     *   <LI> all constant pool entries should have size the same as indicated by their type tag.
    102     *   <LI> there are exactly interfaces_count many entries in the interfaces array of the class file.
    103     *   <LI> there are exactly fields_count many entries in the fields array of the class file.
    104     *   <LI> there are exactly methods_count many entries in the methods array of the class file.
    105     *   <LI> there are exactly attributes_count many entries in the attributes array of the class file,
    106     *        fields, methods, and code attribute.
    107     *   <LI> there should be exactly attribute_length many bytes in each attribute.
    108     *        Inconsistency between attribute_length and the actually size of the attribute content should be uncovered.
    109     *        For example, in an Exceptions attribute, the actual number of exceptions as required by the number_of_exceptions field
    110     *        might yeild an attribute size that doesn't match the attribute_length. Such an anomaly should be detected.
    111     *   <LI> all attributes should have proper length. In particular, under certain context (e.g. while parsing method_info),
    112     *        recognizable attributes (e.g. "Code" attribute) should have correct format (e.g. attribute_length is 2).
    113     *  </UL>
    114     *  <LI> Also, certain constant values are checked for validity:
    115     *  <UL>
    116     *   <LI> The magic number should be 0xCAFEBABE.
    117     *   <LI> The major and minor version numbers are valid.
    118     *   <LI> All the constant pool type tags are recognizable.
    119     *   <LI> All undocumented access flags are masked off before use. Strictly speaking, this is not really a check.
    120     *   <LI> The field this_class should point to a string that represents a legal non-array class name,
    121     *        and this name should be the same as the class file being loaded.
    122     *   <LI> the field super_class should point to a string that represents a legal non-array class name.
    123     *   <LI> Because some of the above checks require cross referencing the constant pool entries,
    124     *        guards are set up to make sure that the referenced entries are of the right type and the indices
    125     *        are within the legal range (0 &lt; index &lt; constant_pool_count).
    126     *  </UL>
    127     *  <LI> Extra checks done in pass 1:
    128     *  <UL>
    129     *   <LI> the constant values of static fields should have the same type as the fields.
    130     *   <LI> the number of words in a parameter list does not exceed 255 and locals_max.
    131     *   <LI> the name and signature of fields and methods are verified to be of legal format.
    132     *  </UL>
    133     * </UL>
    134     * (From the Paper <A HREF="http://www.cs.sfu.ca/people/GradStudents/pwfong/personal/JVM/pass1/">
    135     * The Mysterious Pass One, first draft, September 2, 1997</A>.)
    136     *
    137     * <P>However, most of this is done by parsing a class file or generating a class file into BCEL's internal data structure.
    138     * <B>Therefore, all that is really done here is look up the class file from BCEL's repository.</B>
    139     * This is also motivated by the fact that some omitted things
    140     * (like the check for extra bytes at the end of the class file) are handy when actually using BCEL to repair a class file
    141     * (otherwise you would not be able to load it into BCEL).</P>
    142     *
    143     * @see org.apache.bcel.Repository
    144     * @see org.apache.bcel.Const#JVM_CLASSFILE_MAGIC
    145     */
    146    @Override
    147    public VerificationResult do_verify() {
    148        JavaClass jc;
    149        try{
    150            jc = getJavaClass();    //loads in the class file if not already done.
    151
    152            if (jc != null) {
    153                /* If we find more constraints to check, we should do this in an own method. */
    154                if (! myOwner.getClassName().equals(jc.getClassName())) {
    155                    // This should maybe caught by BCEL: In case of renamed .class files we get wrong
    156                    // JavaClass objects here.
    157                    throw new LoadingException("Wrong name: the internal name of the .class file '"+jc.getClassName()+
    158                        "' does not match the file's name '"+myOwner.getClassName()+"'.");
    159                }
    160            }
    161
    162        }
    163        catch(final LoadingException e) {
    164            return new VerificationResult(VerificationResult.VERIFIED_REJECTED, e.getMessage());
    165        }
    166        catch(final ClassFormatException e) {
    167            return new VerificationResult(VerificationResult.VERIFIED_REJECTED, e.getMessage());
    168        }
    169        catch(final RuntimeException e) {
    170            // BCEL does not catch every possible RuntimeException; e.g. if
    171            // a constant pool index is referenced that does not exist.
    172            return new VerificationResult(VerificationResult.VERIFIED_REJECTED, "Parsing via BCEL did not succeed. "+
    173                e.getClass().getName()+" occured:\n"+Utility.getStackTrace(e));
    174        }
    175
    176        if (jc != null) {
    177            return VerificationResult.VR_OK;
    178        }
    179        //TODO: Maybe change Repository's behaviour to throw a LoadingException instead of just returning "null"
    180        //      if a class file cannot be found or in another way be looked up.
    181        return new VerificationResult(VerificationResult.VERIFIED_REJECTED, "Repository.lookup() failed. FILE NOT FOUND?");
    182    }
    183
    184    /**
    185     * Currently this returns an empty array of String.
    186     * One could parse the error messages of BCEL
    187     * (written to java.lang.System.err) when loading
    188     * a class file such as detecting unknown attributes
    189     * or trailing garbage at the end of a class file.
    190     * However, Markus Dahm does not like the idea so this
    191     * method is currently useless and therefore marked as
    192     * <B>TODO</B>.
    193     */
    194    @Override
    195    public String[] getMessages() {
    196        // This method is only here to override the javadoc-comment.
    197        return super.getMessages();
    198    }
    199
    200}