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 < index < 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}