📄 pass2verifier.java
字号:
package org.apache.bcel.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 apache@apache.org.
*
* 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
* <http://www.apache.org/>.
*/
import org.apache.bcel.Constants;
import org.apache.bcel.Repository;
import org.apache.bcel.classfile.*;
import org.apache.bcel.classfile.Deprecated;
import org.apache.bcel.classfile.EmptyVisitor; // Use _this_ one!
import org.apache.bcel.classfile.Visitor; // Use _this_ one!
import org.apache.bcel.generic.*;
import org.apache.bcel.verifier.*;
import org.apache.bcel.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 2006/09/04 15:43:18 andos Exp $
* @author <A HREF="http://www.inf.fu-berlin.de/~ehaase"/>Enver Haase</A>
* @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 <B>null</B> 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
* <B>Repository.lookupClass(myOwner.getClassname()).getMethods()[method_nr];</B>.
* 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.<BR>
* Note that most referenced classes are <B>not</B> 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.<BR>
* 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 org.apache.bcel.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
* <B>final</B> 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<String> hs = new HashSet<String>(); // 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 <B>final</B> methods are not overridden.
* <B>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).</B>
*
* @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<String, String> hashmap = new HashMap<String, String>();
JavaClass jc = Repository.lookupClass(myOwner.getClassName());
int supidx = -1;
while (supidx != 0){
supidx = jc.getSuperclassNameIndex();
Method[] methods = jc.getMethods();
for (int i=0; i<methods.length; i++){
String name_and_sig = (methods[i].getName()+methods[i].getSignature());
if (hashmap.containsKey(name_and_sig)){
if (methods[i].isFinal()){
throw new ClassConstraintException("Method '"+name_and_sig+"' in class '"+hashmap.get(name_and_sig)+"' overrides the final (not-overridable) definition in class '"+jc.getClassName()+"'.");
}
else{
if (!methods[i].isStatic()){ // static methods don't inherit
hashmap.put(name_and_sig, jc.getClassName());
}
}
}
else{
if (!methods[i].isStatic()){ // static methods don't inherit
hashmap.put(name_and_sig, jc.getClassName());
}
}
}
jc = Repository.lookupClass(jc.getSuperclassName()); // Well, for OBJECT this returns OBJECT so it works (could return anything but must not throw an Exception).
}
}
/**
* Ensures that the constant pool entries satisfy the static constraints
* as described in The Java Virtual Machine Specification, 2nd Edition.
*
* @throws ClassConstraintException otherwise.
*/
private void constant_pool_entries_satisfy_static_constraints(){
// Most of the consistency is handled internally by BCEL; here
// we only have to verify if the indices of the constants point
// to constants of the appropriate type and such.
JavaClass jc = Repository.lookupClass(myOwner.getClassName());
new CPESSC_Visitor(jc); // constructor implicitely traverses jc
}
/**
* A Visitor class that ensures the constant pool satisfies the static
* constraints.
* The visitXXX() methods throw ClassConstraintException instances otherwise.
*
* @see #constant_pool_entries_satisfy_static_constraints()
*/
private class CPESSC_Visitor extends org.apache.bcel.classfile.EmptyVisitor implements Visitor{
private Class CONST_Class;
/*
private Class CONST_Fieldref;
private Class CONST_Methodref;
private Class CONST_InterfaceMethodref;
*/
private Class CONST_String;
private Class CONST_Integer;
private Class CONST_Float;
private Class CONST_Long;
private Class CONST_Double;
private Class CONST_NameAndType;
private Class CONST_Utf8;
private final JavaClass jc;
private final ConstantPool cp; // ==jc.getConstantPool() -- only here to save typing work and computing power.
private final int cplen; // == cp.getLength() -- to save computing power.
private DescendingVisitor carrier;
private HashSet<String> field_names = new HashSet<String>();
private HashSet<String> field_names_and_desc = new HashSet<String>();
private HashSet<String> method_names_and_desc = new HashSet<String>();
private CPESSC_Visitor(JavaClass _jc){
jc = _jc;
cp = _jc.getConstantPool();
cplen = cp.getLength();
CONST_Class = org.apache.bcel.classfile.ConstantClass.class;
/*
CONST_Fieldref = org.apache.bcel.classfile.ConstantFieldref.class;
CONST_Methodref = org.apache.bcel.classfile.ConstantMethodref.class;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -