/* * 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: *
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(); } }