View Javadoc
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   */ 
18  package org.apache.bcel.verifier.statics;
19  
20  
21  import org.apache.bcel.Repository;
22  import org.apache.bcel.classfile.ClassFormatException;
23  import org.apache.bcel.classfile.JavaClass;
24  import org.apache.bcel.verifier.PassVerifier;
25  import org.apache.bcel.verifier.VerificationResult;
26  import org.apache.bcel.verifier.Verifier;
27  import org.apache.bcel.verifier.exc.LoadingException;
28  import org.apache.bcel.verifier.exc.Utility;
29  
30  /**
31   * This PassVerifier verifies a class file according to pass 1 as
32   * described in The Java Virtual Machine Specification, 2nd edition.
33   * More detailed information is to be found at the do_verify() method's
34   * documentation.
35   *
36   * @version $Id: Pass1Verifier.html 992795 2016-07-14 11:53:52Z britter $
37   * @see #do_verify()
38   */
39  public final class Pass1Verifier extends PassVerifier{
40      /**
41       * DON'T USE THIS EVEN PRIVATELY! USE getJavaClass() INSTEAD.
42       * @see #getJavaClass()
43       */
44      private JavaClass jc;
45  
46      /**
47       * The Verifier that created this.
48       */
49      private final Verifier myOwner;
50  
51      /** 
52       * Used to load in and return the myOwner-matching JavaClass object when needed.
53       * Avoids loading in a class file when it's not really needed!
54       */
55      private JavaClass getJavaClass() {
56          if (jc == null) {
57              try {
58                  jc = Repository.lookupClass(myOwner.getClassName());
59              } catch (final ClassNotFoundException e) {
60                  // FIXME: currently, Pass1Verifier treats jc == null as a special
61                  // case, so we don't need to do anything here.  A better solution
62                  // would be to simply throw the ClassNotFoundException
63                  // out of this method.
64              }
65          }
66          return jc;
67      }
68  
69      /**
70       * Should only be instantiated by a Verifier.
71       *
72       * @see Verifier
73       */
74      public Pass1Verifier(final Verifier owner) {
75          myOwner = owner;
76      }
77  
78      /**
79       * Pass-one verification basically means loading in a class file.
80       * The Java Virtual Machine Specification is not too precise about
81       * what makes the difference between passes one and two.
82       * The answer is that only pass one is performed on a class file as
83       * long as its resolution is not requested; whereas pass two and
84       * pass three are performed during the resolution process.
85       * Only four constraints to be checked are explicitly stated by
86       * The Java Virtual Machine Specification, 2nd edition:
87       * <UL>
88       *  <LI>The first four bytes must contain the right magic number (0xCAFEBABE).
89       *  <LI>All recognized attributes must be of the proper length.
90       *  <LI>The class file must not be truncated or have extra bytes at the end.
91       *  <LI>The constant pool must not contain any superficially unrecognizable information.
92       * </UL>
93       * A more in-depth documentation of what pass one should do was written by
94       * <A HREF=mailto:pwfong@cs.sfu.ca>Philip W. L. Fong</A>:
95       * <UL>
96       *  <LI> the file should not be truncated.
97       *  <LI> the file should not have extra bytes at the end.
98       *  <LI> all variable-length structures should be well-formatted:
99       *  <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 }