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, &#247;2.7, &#247;2.7.1, &#247;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 + -
显示快捷键?