📄 pass2verifier.java
字号:
CONST_Integer = org.apache.bcel.classfile.ConstantInteger.class; CONST_Float = org.apache.bcel.classfile.ConstantFloat.class; CONST_Long = org.apache.bcel.classfile.ConstantLong.class; CONST_Double = org.apache.bcel.classfile.ConstantDouble.class; CONST_NameAndType = org.apache.bcel.classfile.ConstantNameAndType.class; CONST_Utf8 = org.apache.bcel.classfile.ConstantUtf8.class; carrier = new DescendingVisitor(_jc, this); carrier.visit(); } private void checkIndex(Node referrer, int index, Class shouldbe){ if ((index < 0) || (index >= 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<atts.length; i++){ if ((! (atts[i] instanceof SourceFile)) && (! (atts[i] instanceof Deprecated)) && (! (atts[i] instanceof InnerClasses)) && (! (atts[i] instanceof Synthetic))){ addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of the ClassFile structure '"+tostring(obj)+"' is unknown and will therefore be ignored."); } if (atts[i] instanceof SourceFile){ if (foundSourceFile == false) foundSourceFile = true; else throw new ClassConstraintException("A ClassFile structure (like '"+tostring(obj)+"') may have no more than one SourceFile attribute."); //vmspec2 4.7.7 } if (atts[i] instanceof InnerClasses){ if (foundInnerClasses == false) foundInnerClasses = true; else{ if (hasInnerClass){ throw new ClassConstraintException("A Classfile structure (like '"+tostring(obj)+"') must have exactly one InnerClasses attribute if at least one Inner Class is referenced (which is the case). More than one InnerClasses attribute was found."); } } if (!hasInnerClass){ addMessage("No referenced Inner Class found, but InnerClasses attribute '"+tostring(atts[i])+"' found. Strongly suggest removal of that attribute."); } } } if (hasInnerClass && !foundInnerClasses){ //throw new ClassConstraintException("A Classfile structure (like '"+tostring(obj)+"') must have exactly one InnerClasses attribute if at least one Inner Class is referenced (which is the case). No InnerClasses attribute was found."); //vmspec2, page 125 says it would be a constraint: but existing verifiers //don't check it and javac doesn't satisfy it when it comes to anonymous //inner classes addMessage("A Classfile structure (like '"+tostring(obj)+"') must have exactly one InnerClasses attribute if at least one Inner Class is referenced (which is the case). No InnerClasses attribute was found."); } } ///////////////////////////// // CONSTANTS (vmspec2 4.4) // ///////////////////////////// public void visitConstantClass(ConstantClass obj){ if (obj.getTag() != Constants.CONSTANT_Class){ throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); } checkIndex(obj, obj.getNameIndex(), CONST_Utf8); } public void visitConstantFieldref(ConstantFieldref obj){ if (obj.getTag() != Constants.CONSTANT_Fieldref){ throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); } checkIndex(obj, obj.getClassIndex(), CONST_Class); checkIndex(obj, obj.getNameAndTypeIndex(), CONST_NameAndType); } public void visitConstantMethodref(ConstantMethodref obj){ if (obj.getTag() != Constants.CONSTANT_Methodref){ throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); } checkIndex(obj, obj.getClassIndex(), CONST_Class); checkIndex(obj, obj.getNameAndTypeIndex(), CONST_NameAndType); } public void visitConstantInterfaceMethodref(ConstantInterfaceMethodref obj){ if (obj.getTag() != Constants.CONSTANT_InterfaceMethodref){ throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); } checkIndex(obj, obj.getClassIndex(), CONST_Class); checkIndex(obj, obj.getNameAndTypeIndex(), CONST_NameAndType); } public void visitConstantString(ConstantString obj){ if (obj.getTag() != Constants.CONSTANT_String){ throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); } checkIndex(obj, obj.getStringIndex(), CONST_Utf8); } public void visitConstantInteger(ConstantInteger obj){ if (obj.getTag() != Constants.CONSTANT_Integer){ throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); } // no indices to check } public void visitConstantFloat(ConstantFloat obj){ if (obj.getTag() != Constants.CONSTANT_Float){ throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); } //no indices to check } public void visitConstantLong(ConstantLong obj){ if (obj.getTag() != Constants.CONSTANT_Long){ throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); } //no indices to check } public void visitConstantDouble(ConstantDouble obj){ if (obj.getTag() != Constants.CONSTANT_Double){ throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); } //no indices to check } public void visitConstantNameAndType(ConstantNameAndType obj){ if (obj.getTag() != Constants.CONSTANT_NameAndType){ throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); } checkIndex(obj, obj.getNameIndex(), CONST_Utf8); //checkIndex(obj, obj.getDescriptorIndex(), CONST_Utf8); //inconsistently named in BCEL, see below. checkIndex(obj, obj.getSignatureIndex(), CONST_Utf8); } public void visitConstantUtf8(ConstantUtf8 obj){ if (obj.getTag() != Constants.CONSTANT_Utf8){ throw new ClassConstraintException("Wrong constant tag in '"+tostring(obj)+"'."); } //no indices to check } ////////////////////////// // FIELDS (vmspec2 4.5) // ////////////////////////// public void visitField(Field obj){ if (jc.isClass()){ int maxone=0; if (obj.isPrivate()) maxone++; if (obj.isProtected()) maxone++; if (obj.isPublic()) maxone++; if (maxone > 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 t = Type.getType(sig); } 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<atts.length; i++){ if ((! (atts[i] instanceof ConstantValue)) && (! (atts[i] instanceof Synthetic)) && (! (atts[i] instanceof Deprecated))){ addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of Field '"+tostring(obj)+"' is unknown and will therefore be ignored."); } if (! (atts[i] instanceof ConstantValue)){ addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of Field '"+tostring(obj)+"' is not a ConstantValue and is therefore only of use for debuggers and such."); } } } /////////////////////////// // METHODS (vmspec2 4.6) // /////////////////////////// public void visitMethod(Method obj){ checkIndex(obj, obj.getNameIndex(), CONST_Utf8); String name = obj.getName(); if (! validMethodName(name, true)){ throw new ClassConstraintException("Method '"+tostring(obj)+"' has illegal name '"+name+"'."); } // A descriptor is often named signature in BCEL checkIndex(obj, obj.getSignatureIndex(), CONST_Utf8); String sig = ((ConstantUtf8) (cp.getConstant(obj.getSignatureIndex()))).getBytes(); // Method's signature(=descriptor) Type t; Type[] ts; // needed below the try block. try{ t = Type.getReturnType(sig); ts = Type.getArgumentTypes(sig); } catch (ClassFormatError cfe){ // Well, BCEL sometimes is a little harsh describing exceptional situations. throw new ClassConstraintException("Illegal descriptor (==signature) '"+sig+"' used by Method '"+tostring(obj)+"'."); } // Check if referenced objects exist. Type act = t; if (act instanceof ArrayType) act = ((ArrayType) act).getBasicType(); if (act instanceof ObjectType){ Verifier v = VerifierFactory.getVerifier( ((ObjectType) act).getClassName() ); VerificationResult vr = v.doPass1(); if (vr != VerificationResult.VR_OK) { throw new ClassConstraintException("Method '"+tostring(obj)+"' has a return type that does not pass verification pass 1: '"+vr+"'."); } } for (int i=0; i<ts.length; i++){ act = ts[i]; if (act instanceof ArrayType) act = ((ArrayType) act).getBasicType(); if (act instanceof ObjectType){ Verifier v = VerifierFactory.getVerifier( ((ObjectType) act).getClassName() ); VerificationResult vr = v.doPass1(); if (vr != VerificationResult.VR_OK) { throw new ClassConstraintException("Method '"+tostring(obj)+"' has an argument type that does not pass verification pass 1: '"+vr+"'."); } } } // Nearly forgot this! Funny return values are allowed, but a non-empty arguments list makes a different method out of it! if (name.equals(STATIC_INITIALIZER_NAME) && (ts.length != 0)){ throw new ClassConstraintException("Method '"+tostring(obj)+"' has illegal name '"+name+"'. It's name resembles the class or interface initialization method which it isn't because of its arguments (==descriptor)."); } if (jc.isClass()){ int maxone=0; if (obj.isPrivate()) maxone++; if (obj.isProtected()) maxone++; if (obj.isPublic()) maxone++; if (maxone > 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."); } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -