pass2verifier.java
来自「JAVA的一些源码 JAVA2 STANDARD EDITION DEVELO」· Java 代码 · 共 1,336 行 · 第 1/4 页
JAVA
1,336 行
String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); if (! name.equals("LineNumberTable")){ throw new ClassConstraintException("The LineNumberTable attribute '"+tostring(obj)+"' is not correctly named 'LineNumberTable' but '"+name+"'."); } //In JustIce,this check is delayed to Pass 3a. //LineNumber[] linenumbers = obj.getLineNumberTable(); // ...validity check... } public void visitLocalVariableTable(LocalVariableTable obj){//vmspec2 4.7.9 //In JustIce,this check is partially delayed to Pass 3a. //The other part can be found in the visitCode(Code) method. } //////////////////////////////////////////////////// // MISC-structure-ATTRIBUTES (vmspec2 4.7.1, 4.7) // //////////////////////////////////////////////////// public void visitUnknown(Unknown obj){//vmspec2 4.7.1 // Represents an unknown attribute. checkIndex(obj, obj.getNameIndex(), CONST_Utf8); // Maybe only misnamed? Give a (warning) message. addMessage("Unknown attribute '"+tostring(obj)+"'. This attribute is not known in any context!"); } ////////// // BCEL // ////////// public void visitLocalVariable(LocalVariable obj){ // This does not represent an Attribute but is only // related to internal BCEL data representation. // see visitLocalVariableTable(LocalVariableTable) } public void visitCodeException(CodeException obj){ // Code constraints are checked in Pass3 (3a and 3b). // This does not represent an Attribute but is only // related to internal BCEL data representation. // see visitCode(Code) } public void visitConstantPool(ConstantPool obj){ // No need to. We're piggybacked by the DescendingVisitor. // This does not represent an Attribute but is only // related to internal BCEL data representation. } public void visitInnerClass(InnerClass obj){ // This does not represent an Attribute but is only // related to internal BCEL data representation. } public void visitLineNumber(LineNumber obj){ // This does not represent an Attribute but is only // related to internal BCEL data representation. // see visitLineNumberTable(LineNumberTable) } } /** * Ensures that the ConstantCP-subclassed entries of the constant * pool are valid. According to "Yellin: Low Level Security in Java", * this method does not verify the existence of referenced entities * (such as classes) but only the formal correctness (such as well-formed * signatures). * The visitXXX() methods throw ClassConstraintException instances otherwise. * <B>Precondition: index-style cross referencing in the constant * pool must be valid. Simply invoke constant_pool_entries_satisfy_static_constraints() * before.</B> * * @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. * <B>Precondition: index-style cross referencing in the constant * pool must be valid.</B> * * @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 JavaClass jc; private final ConstantPool cp; // ==jc.getConstantPool() -- only here to save typing work. private FAMRAV_Visitor(JavaClass _jc){ jc = _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 t = Type.getType(sig); } 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); Type[] ts = Type.getArgumentTypes(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); Type[] ts = Type.getArgumentTypes(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){ // Are there 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<name.length(); i++){ if (!Character.isJavaIdentifierPart(name.charAt(i))) return false; } return true; } /** * This method returns true if and only if the supplied String * represents a valid Java interface method name that may be * referenced by ConstantInterfaceMethodref objects. */ private static boolean validInterfaceMethodName(String name){ // I guess we should assume special names forbidden here. if (name.startsWith("<")) return false; return validJavaLangMethodName(name); } /** * This method returns true if and only if the supplied String * represents a valid Java identifier (so-called simple name). */ private static boolean validJavaIdentifier(String name){ // vmspec2 2.7, vmspec2 2.2 if (!Character.isJavaIdentifierStart(name.charAt(0))) return false; for (int i=1; i<name.length(); i++){ if (!Character.isJavaIdentifierPart(name.charAt(i))) return false; } return true; } /** * This method returns true if and only if the supplied String * represents a valid Java field name. */ private static boolean validFieldName(String name){ // vmspec2 2.7, vmspec2 2.2 return validJavaIdentifier(name); } /** * This class serves for finding out if a given JavaClass' ConstantPool * references an Inner Class. * The Java Virtual Machine Specification, Second Edition is not very precise * about when an "InnerClasses" attribute has to appear. However, it states that * there has to be exactly one InnerClasses attribute in the ClassFile structure * if the constant pool of a class or interface refers to any class or interface * "that is not a member of a package". Sun does not mean "member of the default * package". In "Inner Classes Specification" they point out how a "bytecode name" * is derived so one has to deduce what a class name of a class "that is not a * member of a package" looks like: there is at least one character in the byte- * code name that cannot be part of a legal Java Language Class name (and not equal * to '/'). This assumption is wrong as the delimiter is '$' for which * Character.isJavaIdentifierPart() == true. * Hence, you really run into trouble if you have a toplevel class called * "A$XXX" and another toplevel class called "A" with in inner class called "XXX". * JustIce cannot repair this; please note that existing verifiers at this * time even fail to detect missing InnerClasses attributes in pass 2. */ private class InnerClassDetector extends EmptyVisitor{ private boolean hasInnerClass = false; private JavaClass jc; private ConstantPool cp; private InnerClassDetector(){} // Don't use. /** Constructs an InnerClassDetector working on the JavaClass _jc. */ public InnerClassDetector(JavaClass _jc){ jc = _jc; cp = jc.getConstantPool(); (new DescendingVisitor(jc, this)).visit(); } /** * Returns if the JavaClass this InnerClassDetector is working on * has an Inner Class reference in its constant pool. */ public boolean innerClassReferenced(){ return hasInnerClass; } /** This method casually visits ConstantClass references. */ public void visitConstantClass(ConstantClass obj){ Constant c = cp.getConstant(obj.getNameIndex()); if (c instanceof ConstantUtf8){ //Ignore the case where it's not a ConstantUtf8 here, we'll find out later. String classname = ((ConstantUtf8) c).getBytes(); if (classname.startsWith(jc.getClassName().replace('.','/')+"$")){ hasInnerClass = true; } } } } /** * This method is here to save typing work and improve code readability. */ private static String tostring(Node n){ return new StringRepresentation(n).toString(); }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?