All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.bcel.verifier.statics.Pass1Verifier Maven / Gradle / Ivy

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


import org.apache.bcel.Repository;
import org.apache.bcel.classfile.ClassFormatException;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.verifier.PassVerifier;
import org.apache.bcel.verifier.VerificationResult;
import org.apache.bcel.verifier.Verifier;
import org.apache.bcel.verifier.exc.LoadingException;
import org.apache.bcel.verifier.exc.Utility;

/**
 * This PassVerifier verifies a class file according to pass 1 as
 * described in The Java Virtual Machine Specification, 2nd edition.
 * More detailed information is to be found at the do_verify() method's
 * documentation.
 *
 * @version $Id$
 * @see #do_verify()
 */
public final class Pass1Verifier extends PassVerifier{
    /**
     * DON'T USE THIS EVEN PRIVATELY! USE getJavaClass() INSTEAD.
     * @see #getJavaClass()
     */
    private JavaClass jc;

    /**
     * The Verifier that created this.
     */
    private final Verifier myOwner;

    /**
     * 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) {
            try {
                jc = Repository.lookupClass(myOwner.getClassName());
            } catch (final ClassNotFoundException e) {
                // FIXME: currently, Pass1Verifier treats jc == null as a special
                // case, so we don't need to do anything here.  A better solution
                // would be to simply throw the ClassNotFoundException
                // out of this method.
            }
        }
        return jc;
    }

    /**
     * Should only be instantiated by a Verifier.
     *
     * @see Verifier
     */
    public Pass1Verifier(final Verifier owner) {
        myOwner = owner;
    }

    /**
     * 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 explicitly stated by
     * The Java Virtual Machine Specification, 2nd edition:
     * 
    *
  • The first four bytes must contain the right magic number (0xCAFEBABE). *
  • All recognized attributes must be of the proper length. *
  • The class file must not be truncated or have extra bytes at the end. *
  • The constant pool must not contain any superficially unrecognizable information. *
* A more in-depth documentation of what pass one should do was written by * Philip W. L. Fong: *
    *
  • the file should not be truncated. *
  • the file should not have extra bytes at the end. *
  • all variable-length structures should be well-formatted: *
      *
    • there should only be constant_pool_count-1 many entries in the constant pool. *
    • all constant pool entries should have size the same as indicated by their type tag. *
    • there are exactly interfaces_count many entries in the interfaces array of the class file. *
    • there are exactly fields_count many entries in the fields array of the class file. *
    • there are exactly methods_count many entries in the methods array of the class file. *
    • there are exactly attributes_count many entries in the attributes array of the class file, * fields, methods, and code attribute. *
    • 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. *
    • 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). *
    *
  • Also, certain constant values are checked for validity: *
      *
    • The magic number should be 0xCAFEBABE. *
    • The major and minor version numbers are valid. *
    • All the constant pool type tags are recognizable. *
    • All undocumented access flags are masked off before use. Strictly speaking, this is not really a check. *
    • 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. *
    • the field super_class should point to a string that represents a legal non-array class name. *
    • 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). *
    *
  • Extra checks done in pass 1: *
      *
    • the constant values of static fields should have the same type as the fields. *
    • the number of words in a parameter list does not exceed 255 and locals_max. *
    • the name and signature of fields and methods are verified to be of legal format. *
    *
* (From the Paper * The Mysterious Pass One, first draft, September 2, 1997.) * *

However, most of this is done by parsing a class file or generating a class file into BCEL's internal data structure. * Therefore, all that is really done here is look up the class file from BCEL's repository. * 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.apache.bcel.Repository * @see org.apache.bcel.Const#JVM_CLASSFILE_MAGIC */ @Override 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(final LoadingException e) { return new VerificationResult(VerificationResult.VERIFIED_REJECTED, e.getMessage()); } catch(final ClassFormatException e) { return new VerificationResult(VerificationResult.VERIFIED_REJECTED, e.getMessage()); } catch(final 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; } //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?"); } /** * Currently this returns an empty array of String. * One could parse the error messages of BCEL * (written to java.lang.System.err) when loading * a class file such as detecting unknown attributes * or trailing garbage at the end of a class file. * However, Markus Dahm does not like the idea so this * method is currently useless and therefore marked as * TODO. */ @Override public String[] getMessages() { // This method is only here to override the javadoc-comment. return super.getMessages(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy