📄 pass2verifier.java
字号:
}
int localindex = localvariables[i].getIndex();
if ( ( (t==Type.LONG || t==Type.DOUBLE)? localindex+1:localindex) >= 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; i<exc_indices.length; i++){
checkIndex(obj, exc_indices[i], CONST_Class);
ConstantClass cc = (ConstantClass) (cp.getConstant(exc_indices[i]));
checkIndex(cc, cc.getNameIndex(), CONST_Utf8); // cannot be sure this ConstantClass has already been visited (checked)!
String cname = ((ConstantUtf8) cp.getConstant(cc.getNameIndex())).getBytes().replace('/','.'); //convert internal notation on-the-fly to external notation
Verifier v = VerifierFactory.getVerifier(cname);
VerificationResult vr = v.doPass1();
if (vr != VerificationResult.VR_OK){
throw new ClassConstraintException("Exceptions attribute '"+tostring(obj)+"' references '"+cname+"' as an Exception but it does not pass verification pass 1: "+vr);
}
else{
// We cannot safely trust any other "instanceof" mechanism. We need to transitively verify
// the ancestor hierarchy.
JavaClass e = Repository.lookupClass(cname);
JavaClass t = Repository.lookupClass(Type.THROWABLE.getClassName());
JavaClass o = Repository.lookupClass(Type.OBJECT.getClassName());
while (e != o){
if (e == t) break; // It's a subclass of Throwable, OKAY, leave.
v = VerifierFactory.getVerifier(e.getSuperclassName());
vr = v.doPass1();
if (vr != VerificationResult.VR_OK){
throw new ClassConstraintException("Exceptions attribute '"+tostring(obj)+"' references '"+cname+"' as an Exception but '"+e.getSuperclassName()+"' in the ancestor hierachy does not pass verification pass 1: "+vr);
}
else{
e = Repository.lookupClass(e.getSuperclassName());
}
}
if (e != t) throw new ClassConstraintException("Exceptions attribute '"+tostring(obj)+"' references '"+cname+"' as an Exception but it is not a subclass of '"+t.getClassName()+"'.");
}
}
}
// SYNTHETIC: see above
// DEPRECATED: see above
//////////////////////////////////////////////////////////////
// code_attribute-structure-ATTRIBUTES (vmspec2 4.7.3, 4.7) //
//////////////////////////////////////////////////////////////
public void visitLineNumberTable(LineNumberTable obj){//vmspec2 4.7.8
checkIndex(obj, obj.getNameIndex(), CONST_Utf8);
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 org.apache.bcel.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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -