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

com.sun.org.apache.bcel.internal.verifier.statics.Pass2Verifier Maven / Gradle / Ivy

The newest version!
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 * 
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */

package com.sun.org.apache.bcel.internal.verifier.statics;

/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" and
 *    "Apache BCEL" must not be used to endorse or promote products
 *    derived from this software without prior written permission. For
 *    written permission, please contact [email protected].
 *
 * 5. Products derived from this software may not be called "Apache",
 *    "Apache BCEL", nor may "Apache" appear in their name, without
 *    prior written permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * .
 */

import com.sun.org.apache.bcel.internal.Constants;
import com.sun.org.apache.bcel.internal.Repository;
import com.sun.org.apache.bcel.internal.classfile.*;
import com.sun.org.apache.bcel.internal.classfile.DescendingVisitor; // Use _this_ one!
import com.sun.org.apache.bcel.internal.classfile.EmptyVisitor; // Use _this_ one!
import com.sun.org.apache.bcel.internal.classfile.Visitor; // Use _this_ one!
import com.sun.org.apache.bcel.internal.generic.*;
import com.sun.org.apache.bcel.internal.verifier.*;
import com.sun.org.apache.bcel.internal.verifier.exc.*;
import java.util.HashMap;
import java.util.HashSet;

/**
 * This PassVerifier verifies a class file according to
 * pass 2 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: Pass2Verifier.java,v 1.3 2007-07-19 04:35:00 ofung Exp $
 * @author Enver Haase
 * @see #do_verify()
 */
public final class Pass2Verifier extends PassVerifier implements Constants{

	/**
	 * The LocalVariableInfo instances used by Pass3bVerifier.
	 * localVariablesInfos[i] denotes the information for the
	 * local variables of method number i in the
	 * JavaClass this verifier operates on.
	 */
	private LocalVariablesInfo[] localVariablesInfos;
	
	/** The Verifier that created this. */
	private Verifier myOwner;

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

	/**
	 * Returns a LocalVariablesInfo object containing information
	 * about the usage of the local variables in the Code attribute
	 * of the said method or null if the class file this
	 * Pass2Verifier operates on could not be pass-2-verified correctly.
	 * The method number method_nr is the method you get using
	 * Repository.lookupClass(myOwner.getClassname()).getMethods()[method_nr];.
	 * You should not add own information. Leave that to JustIce.
	 */
	public LocalVariablesInfo getLocalVariablesInfo(int method_nr){
		if (this.verify() != VerificationResult.VR_OK) return null; // It's cached, don't worry.
		if (method_nr < 0 || method_nr >= localVariablesInfos.length){
			throw new AssertionViolatedException("Method number out of range.");
		}
		return localVariablesInfos[method_nr];
	}
	
	/**
	 * Pass 2 is the pass where static properties of the
	 * class file are checked without looking into "Code"
	 * arrays of methods.
	 * This verification pass is usually invoked when
	 * a class is resolved; and it may be possible that
	 * this verification pass has to load in other classes
	 * such as superclasses or implemented interfaces.
	 * Therefore, Pass 1 is run on them.
* Note that most referenced classes are not loaded * in for verification or for an existance check by this * pass; only the syntactical correctness of their names * and descriptors (a.k.a. signatures) is checked.
* Very few checks that conceptually belong here * are delayed until pass 3a in JustIce. JustIce does * not only check for syntactical correctness but also * for semantical sanity - therefore it needs access to * the "Code" array of methods in a few cases. Please * see the pass 3a documentation, too. * * @see com.sun.org.apache.bcel.internal.verifier.statics.Pass3aVerifier */ public VerificationResult do_verify(){ VerificationResult vr1 = myOwner.doPass1(); if (vr1.equals(VerificationResult.VR_OK)){ // For every method, we could have information about the local variables out of LocalVariableTable attributes of // the Code attributes. localVariablesInfos = new LocalVariablesInfo[Repository.lookupClass(myOwner.getClassName()).getMethods().length]; VerificationResult vr = VerificationResult.VR_OK; // default. try{ constant_pool_entries_satisfy_static_constraints(); field_and_method_refs_are_valid(); every_class_has_an_accessible_superclass(); final_methods_are_not_overridden(); } catch (ClassConstraintException cce){ vr = new VerificationResult(VerificationResult.VERIFIED_REJECTED, cce.getMessage()); } return vr; } else return VerificationResult.VR_NOTYET; } /** * Ensures that every class has a super class and that * final classes are not subclassed. * This means, the class this Pass2Verifier operates * on has proper super classes (transitively) up to * java.lang.Object. * The reason for really loading (and Pass1-verifying) * all of those classes here is that we need them in * Pass2 anyway to verify no final methods are overridden * (that could be declared anywhere in the ancestor hierarchy). * * @throws ClassConstraintException otherwise. */ private void every_class_has_an_accessible_superclass(){ HashSet hs = new HashSet(); // save class names to detect circular inheritance JavaClass jc = Repository.lookupClass(myOwner.getClassName()); int supidx = -1; while (supidx != 0){ supidx = jc.getSuperclassNameIndex(); if (supidx == 0){ if (jc != Repository.lookupClass(Type.OBJECT.getClassName())){ throw new ClassConstraintException("Superclass of '"+jc.getClassName()+"' missing but not "+Type.OBJECT.getClassName()+" itself!"); } } else{ String supername = jc.getSuperclassName(); if (! hs.add(supername)){ // If supername already is in the list throw new ClassConstraintException("Circular superclass hierarchy detected."); } Verifier v = VerifierFactory.getVerifier(supername); VerificationResult vr = v.doPass1(); if (vr != VerificationResult.VR_OK){ throw new ClassConstraintException("Could not load in ancestor class '"+supername+"'."); } jc = Repository.lookupClass(supername); if (jc.isFinal()){ throw new ClassConstraintException("Ancestor class '"+supername+"' has the FINAL access modifier and must therefore not be subclassed."); } } } } /** * Ensures that final methods are not overridden. * Precondition to run this method: * constant_pool_entries_satisfy_static_constraints() and * every_class_has_an_accessible_superclass() have to be invoked before * (in that order). * * @throws ClassConstraintException otherwise. * @see #constant_pool_entries_satisfy_static_constraints() * @see #every_class_has_an_accessible_superclass() */ private void final_methods_are_not_overridden(){ HashMap hashmap = new HashMap(); JavaClass jc = Repository.lookupClass(myOwner.getClassName()); int supidx = -1; while (supidx != 0){ supidx = jc.getSuperclassNameIndex(); Method[] methods = jc.getMethods(); for (int i=0; i= cplen)){ throw new ClassConstraintException("Invalid index '"+index+"' used by '"+tostring(referrer)+"'."); } Constant c = cp.getConstant(index); if (! shouldbe.isInstance(c)){ /* String isnot = shouldbe.toString().substring(shouldbe.toString().lastIndexOf(".")+1); //Cut all before last "." */ throw new ClassCastException("Illegal constant '"+tostring(c)+"' at index '"+index+"'. '"+tostring(referrer)+"' expects a '"+shouldbe+"'."); } } /////////////////////////////////////// // ClassFile structure (vmspec2 4.1) // /////////////////////////////////////// public void visitJavaClass(JavaClass obj){ Attribute[] atts = obj.getAttributes(); boolean foundSourceFile = false; boolean foundInnerClasses = false; // Is there an InnerClass referenced? // This is a costly check; existing verifiers don't do it! boolean hasInnerClass = new InnerClassDetector(jc).innerClassReferenced(); for (int i=0; i 1){ throw new ClassConstraintException("Field '"+tostring(obj)+"' must only have at most one of its ACC_PRIVATE, ACC_PROTECTED, ACC_PUBLIC modifiers set."); } if (obj.isFinal() && obj.isVolatile()){ throw new ClassConstraintException("Field '"+tostring(obj)+"' must only have at most one of its ACC_FINAL, ACC_VOLATILE modifiers set."); } } else{ // isInterface! if (!obj.isPublic()){ throw new ClassConstraintException("Interface field '"+tostring(obj)+"' must have the ACC_PUBLIC modifier set but hasn't!"); } if (!obj.isStatic()){ throw new ClassConstraintException("Interface field '"+tostring(obj)+"' must have the ACC_STATIC modifier set but hasn't!"); } if (!obj.isFinal()){ throw new ClassConstraintException("Interface field '"+tostring(obj)+"' must have the ACC_FINAL modifier set but hasn't!"); } } if ((obj.getAccessFlags() & ~(ACC_PUBLIC|ACC_PRIVATE|ACC_PROTECTED|ACC_STATIC|ACC_FINAL|ACC_VOLATILE|ACC_TRANSIENT)) > 0){ addMessage("Field '"+tostring(obj)+"' has access flag(s) other than ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_VOLATILE, ACC_TRANSIENT set (ignored)."); } checkIndex(obj, obj.getNameIndex(), CONST_Utf8); String name = obj.getName(); if (! validFieldName(name)){ throw new ClassConstraintException("Field '"+tostring(obj)+"' has illegal name '"+obj.getName()+"'."); } // A descriptor is often named signature in BCEL checkIndex(obj, obj.getSignatureIndex(), CONST_Utf8); String sig = ((ConstantUtf8) (cp.getConstant(obj.getSignatureIndex()))).getBytes(); // Field or Method signature(=descriptor) try{ Type.getType(sig); /* Don't need the return value */ } catch (ClassFormatError cfe){ // sometimes BCEL is a little harsh describing exceptional situations. throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by '"+tostring(obj)+"'."); } String nameanddesc = (name+sig); if (field_names_and_desc.contains(nameanddesc)){ throw new ClassConstraintException("No two fields (like '"+tostring(obj)+"') are allowed have same names and descriptors!"); } if (field_names.contains(name)){ addMessage("More than one field of name '"+name+"' detected (but with different type descriptors). This is very unusual."); } field_names_and_desc.add(nameanddesc); field_names.add(name); Attribute[] atts = obj.getAttributes(); for (int i=0; i 1){ throw new ClassConstraintException("Method '"+tostring(obj)+"' must only have at most one of its ACC_PRIVATE, ACC_PROTECTED, ACC_PUBLIC modifiers set."); } if (obj.isAbstract()){ if (obj.isFinal()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_FINAL modifier set."); if (obj.isNative()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_NATIVE modifier set."); if (obj.isPrivate()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_PRIVATE modifier set."); if (obj.isStatic()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_STATIC modifier set."); if (obj.isStrictfp()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_STRICT modifier set."); if (obj.isSynchronized()) throw new ClassConstraintException("Abstract method '"+tostring(obj)+"' must not have the ACC_SYNCHRONIZED modifier set."); } } else{ // isInterface! if (!name.equals(STATIC_INITIALIZER_NAME)){//vmspec2, p.116, 2nd paragraph if (!obj.isPublic()){ throw new ClassConstraintException("Interface method '"+tostring(obj)+"' must have the ACC_PUBLIC modifier set but hasn't!"); } if (!obj.isAbstract()){ throw new ClassConstraintException("Interface method '"+tostring(obj)+"' must have the ACC_STATIC modifier set but hasn't!"); } if ( obj.isPrivate() || obj.isProtected() || obj.isStatic() || obj.isFinal() || obj.isSynchronized() || obj.isNative() || obj.isStrictfp() ){ throw new ClassConstraintException("Interface method '"+tostring(obj)+"' must not have any of the ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT, ACC_STRICT modifiers set."); } } } // A specific instance initialization method... (vmspec2,Page 116). if (name.equals(CONSTRUCTOR_NAME)){ //..may have at most one of ACC_PRIVATE, ACC_PROTECTED, ACC_PUBLIC set: is checked above. //..may also have ACC_STRICT set, but none of the other flags in table 4.5 (vmspec2, page 115) if ( obj.isStatic() || obj.isFinal() || obj.isSynchronized() || obj.isNative() || obj.isAbstract() ){ throw new ClassConstraintException("Instance initialization method '"+tostring(obj)+"' must not have any of the ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT modifiers set."); } } // Class and interface initialization methods... if (name.equals(STATIC_INITIALIZER_NAME)){ if ((obj.getAccessFlags() & (~ACC_STRICT)) > 0){ addMessage("Class or interface initialization method '"+tostring(obj)+"' has superfluous access modifier(s) set: everything but ACC_STRICT is ignored."); } if (obj.isAbstract()){ throw new ClassConstraintException("Class or interface initialization method '"+tostring(obj)+"' must not be abstract. This contradicts the Java Language Specification, Second Edition (which omits this constraint) but is common practice of existing verifiers."); } } if ((obj.getAccessFlags() & ~(ACC_PUBLIC|ACC_PRIVATE|ACC_PROTECTED|ACC_STATIC|ACC_FINAL|ACC_SYNCHRONIZED|ACC_NATIVE|ACC_ABSTRACT|ACC_STRICT)) > 0){ addMessage("Method '"+tostring(obj)+"' has access flag(s) other than ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT, ACC_STRICT set (ignored)."); } String nameanddesc = (name+sig); if (method_names_and_desc.contains(nameanddesc)){ throw new ClassConstraintException("No two methods (like '"+tostring(obj)+"') are allowed have same names and desciptors!"); } method_names_and_desc.add(nameanddesc); Attribute[] atts = obj.getAttributes(); int num_code_atts = 0; for (int i=0; i= cplen)){ throw new ClassConstraintException("Invalid index '"+index+"' used by '"+tostring(obj)+"'."); } Constant c = cp.getConstant(index); if (CONST_Long.isInstance(c) && field_type.equals(Type.LONG)){ return; } if (CONST_Float.isInstance(c) && field_type.equals(Type.FLOAT)){ return; } if (CONST_Double.isInstance(c) && field_type.equals(Type.DOUBLE)){ return; } if (CONST_Integer.isInstance(c) && (field_type.equals(Type.INT) || field_type.equals(Type.SHORT) || field_type.equals(Type.CHAR) || field_type.equals(Type.BYTE) || field_type.equals(Type.BOOLEAN))){ return; } if (CONST_String.isInstance(c) && field_type.equals(Type.STRING)){ return; } throw new ClassConstraintException("Illegal type of ConstantValue '"+obj+"' embedding Constant '"+c+"'. It is referenced by field '"+tostring(f)+"' expecting a different type: '"+field_type+"'."); } } // SYNTHETIC: see above // DEPRECATED: see above ///////////////////////////////////////////////////////// // method_info-structure-ATTRIBUTES (vmspec2 4.6, 4.7) // ///////////////////////////////////////////////////////// public void visitCode(Code obj){//vmspec2 4.7.3 // No code attribute allowed for native or abstract methods: see visitMethod(Method). // Code array constraints are checked in Pass3 (3a and 3b). checkIndex(obj, obj.getNameIndex(), CONST_Utf8); String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); if (! name.equals("Code")){ throw new ClassConstraintException("The Code attribute '"+tostring(obj)+"' is not correctly named 'Code' but '"+name+"'."); } Method m = null; // satisfy compiler if (!(carrier.predecessor() instanceof Method)){ addMessage("Code attribute '"+tostring(obj)+"' is not declared in a method_info structure but in '"+carrier.predecessor()+"'. Ignored."); return; } else{ m = (Method) carrier.predecessor(); // we can assume this method was visited before; // i.e. the data consistency was verified. } if (obj.getCode().length == 0){ throw new ClassConstraintException("Code array of Code attribute '"+tostring(obj)+"' (method '"+m+"') must not be empty."); } //In JustIce, the check for correct offsets into the code array is delayed to Pass 3a. CodeException[] exc_table = obj.getExceptionTable(); for (int i=0; i= code.getMaxLocals()){ throw new ClassConstraintException("LocalVariableTable attribute '"+tostring(lvt)+"' references a LocalVariable '"+tostring(localvariables[i])+"' with an index that exceeds the surrounding Code attribute's max_locals value of '"+code.getMaxLocals()+"'."); } try{ localVariablesInfos[method_number].add(localindex, localname, localvariables[i].getStartPC(), localvariables[i].getLength(), t); } catch(LocalVariableInfoInconsistentException lviie){ throw new ClassConstraintException("Conflicting information in LocalVariableTable '"+tostring(lvt)+"' found in Code attribute '"+tostring(obj)+"' (method '"+tostring(m)+"'). "+lviie.getMessage()); } }// for all local variables localvariables[i] in the LocalVariableTable attribute atts[a] END num_of_lvt_attribs++; if (num_of_lvt_attribs > obj.getMaxLocals()){ throw new ClassConstraintException("Number of LocalVariableTable attributes of Code attribute '"+tostring(obj)+"' (method '"+tostring(m)+"') exceeds number of local variable slots '"+obj.getMaxLocals()+"' ('There may be no more than one LocalVariableTable attribute per local variable in the Code attribute.')."); } }// if atts[a] instanceof LocalVariableTable END }// for all attributes atts[a] END }// visitCode(Code) END public void visitExceptionTable(ExceptionTable obj){//vmspec2 4.7.4 // incorrectly named, it's the Exceptions attribute (vmspec2 4.7.4) checkIndex(obj, obj.getNameIndex(), CONST_Utf8); String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); if (! name.equals("Exceptions")){ throw new ClassConstraintException("The Exceptions attribute '"+tostring(obj)+"' is not correctly named 'Exceptions' but '"+name+"'."); } int[] exc_indices = obj.getExceptionIndexTable(); for (int i=0; iPrecondition: index-style cross referencing in the constant * pool must be valid. Simply invoke constant_pool_entries_satisfy_static_constraints() * before. * * @throws ClassConstraintException otherwise. * @see #constant_pool_entries_satisfy_static_constraints() */ private void field_and_method_refs_are_valid(){ JavaClass jc = Repository.lookupClass(myOwner.getClassName()); DescendingVisitor v = new DescendingVisitor(jc, new FAMRAV_Visitor(jc)); v.visit(); } /** * A Visitor class that ensures the ConstantCP-subclassed entries * of the constant pool are valid. * Precondition: index-style cross referencing in the constant * pool must be valid. * * @see #constant_pool_entries_satisfy_static_constraints() * @see com.sun.org.apache.bcel.internal.classfile.ConstantCP */ private class FAMRAV_Visitor extends EmptyVisitor implements Visitor{ private final ConstantPool cp; // ==jc.getConstantPool() -- only here to save typing work. private FAMRAV_Visitor(JavaClass _jc){ cp = _jc.getConstantPool(); } public void visitConstantFieldref(ConstantFieldref obj){ if (obj.getTag() != Constants.CONSTANT_Fieldref){ throw new ClassConstraintException("ConstantFieldref '"+tostring(obj)+"' has wrong tag!"); } int name_and_type_index = obj.getNameAndTypeIndex(); ConstantNameAndType cnat = (ConstantNameAndType) (cp.getConstant(name_and_type_index)); String name = ((ConstantUtf8) (cp.getConstant(cnat.getNameIndex()))).getBytes(); // Field or Method name if (!validFieldName(name)){ throw new ClassConstraintException("Invalid field name '"+name+"' referenced by '"+tostring(obj)+"'."); } int class_index = obj.getClassIndex(); ConstantClass cc = (ConstantClass) (cp.getConstant(class_index)); String className = ((ConstantUtf8) (cp.getConstant(cc.getNameIndex()))).getBytes(); // Class Name in internal form if (! validClassName(className)){ throw new ClassConstraintException("Illegal class name '"+className+"' used by '"+tostring(obj)+"'."); } String sig = ((ConstantUtf8) (cp.getConstant(cnat.getSignatureIndex()))).getBytes(); // Field or Method signature(=descriptor) try{ Type.getType(sig); /* Don't need the return value */ } catch (ClassFormatError cfe){ // Well, BCEL sometimes is a little harsh describing exceptional situations. throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by '"+tostring(obj)+"'."); } } public void visitConstantMethodref(ConstantMethodref obj){ if (obj.getTag() != Constants.CONSTANT_Methodref){ throw new ClassConstraintException("ConstantMethodref '"+tostring(obj)+"' has wrong tag!"); } int name_and_type_index = obj.getNameAndTypeIndex(); ConstantNameAndType cnat = (ConstantNameAndType) (cp.getConstant(name_and_type_index)); String name = ((ConstantUtf8) (cp.getConstant(cnat.getNameIndex()))).getBytes(); // Field or Method name if (!validClassMethodName(name)){ throw new ClassConstraintException("Invalid (non-interface) method name '"+name+"' referenced by '"+tostring(obj)+"'."); } int class_index = obj.getClassIndex(); ConstantClass cc = (ConstantClass) (cp.getConstant(class_index)); String className = ((ConstantUtf8) (cp.getConstant(cc.getNameIndex()))).getBytes(); // Class Name in internal form if (! validClassName(className)){ throw new ClassConstraintException("Illegal class name '"+className+"' used by '"+tostring(obj)+"'."); } String sig = ((ConstantUtf8) (cp.getConstant(cnat.getSignatureIndex()))).getBytes(); // Field or Method signature(=descriptor) try{ Type t = Type.getReturnType(sig); if ( name.equals(CONSTRUCTOR_NAME) && (t != Type.VOID) ){ throw new ClassConstraintException("Instance initialization method must have VOID return type."); } } catch (ClassFormatError cfe){ // Well, BCEL sometimes is a little harsh describing exceptional situations. throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by '"+tostring(obj)+"'."); } } public void visitConstantInterfaceMethodref(ConstantInterfaceMethodref obj){ if (obj.getTag() != Constants.CONSTANT_InterfaceMethodref){ throw new ClassConstraintException("ConstantInterfaceMethodref '"+tostring(obj)+"' has wrong tag!"); } int name_and_type_index = obj.getNameAndTypeIndex(); ConstantNameAndType cnat = (ConstantNameAndType) (cp.getConstant(name_and_type_index)); String name = ((ConstantUtf8) (cp.getConstant(cnat.getNameIndex()))).getBytes(); // Field or Method name if (!validInterfaceMethodName(name)){ throw new ClassConstraintException("Invalid (interface) method name '"+name+"' referenced by '"+tostring(obj)+"'."); } int class_index = obj.getClassIndex(); ConstantClass cc = (ConstantClass) (cp.getConstant(class_index)); String className = ((ConstantUtf8) (cp.getConstant(cc.getNameIndex()))).getBytes(); // Class Name in internal form if (! validClassName(className)){ throw new ClassConstraintException("Illegal class name '"+className+"' used by '"+tostring(obj)+"'."); } String sig = ((ConstantUtf8) (cp.getConstant(cnat.getSignatureIndex()))).getBytes(); // Field or Method signature(=descriptor) try{ Type t = Type.getReturnType(sig); if ( name.equals(STATIC_INITIALIZER_NAME) && (t != Type.VOID) ){ addMessage("Class or interface initialization method '"+STATIC_INITIALIZER_NAME+"' usually has VOID return type instead of '"+t+"'. Note this is really not a requirement of The Java Virtual Machine Specification, Second Edition."); } } catch (ClassFormatError cfe){ // Well, BCEL sometimes is a little harsh describing exceptional situations. throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by '"+tostring(obj)+"'."); } } } /** * This method returns true if and only if the supplied String * represents a valid Java class name. */ private static final boolean validClassName(String name){ /* * TODO: implement. * Are there any restrictions? */ return true; } /** * This method returns true if and only if the supplied String * represents a valid method name. * This is basically the same as a valid identifier name in the * Java programming language, but the special name for * the instance initialization method is allowed and the special name * for the class/interface initialization method may be allowed. */ private static boolean validMethodName(String name, boolean allowStaticInit){ if (validJavaLangMethodName(name)) return true; if (allowStaticInit){ return (name.equals(CONSTRUCTOR_NAME) || name.equals(STATIC_INITIALIZER_NAME)); } else{ return name.equals(CONSTRUCTOR_NAME); } } /** * This method returns true if and only if the supplied String * represents a valid method name that may be referenced by * ConstantMethodref objects. */ private static boolean validClassMethodName(String name){ return validMethodName(name, false); } /** * This method returns true if and only if the supplied String * represents a valid Java programming language method name stored as a simple * (non-qualified) name. * Conforming to: The Java Virtual Machine Specification, Second Edition, �2.7, �2.7.1, �2.2. */ private static boolean validJavaLangMethodName(String name){ if (!Character.isJavaIdentifierStart(name.charAt(0))) return false; for (int i=1; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy