📄 pass2verifier.java
字号:
} // A specific instance initialization method... (vmspec2,Page 116). if (name.equals(CONSTRUCTOR_NAME)){ //..may have at most one of ACC_PRIVATE, ACC_PROTECTED, ACC_PUBLIC set: is checked above. //..may also have ACC_STRICT set, but none of the other flags in table 4.5 (vmspec2, page 115) if ( obj.isStatic() || obj.isFinal() || obj.isSynchronized() || obj.isNative() || obj.isAbstract() ){ throw new ClassConstraintException("Instance initialization method '"+tostring(obj)+"' must not have any of the ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT modifiers set."); } } // Class and interface initialization methods... if (name.equals(STATIC_INITIALIZER_NAME)){ if ((obj.getAccessFlags() & (~ACC_STRICT)) > 0){ addMessage("Class or interface initialization method '"+tostring(obj)+"' has superfluous access modifier(s) set: everything but ACC_STRICT is ignored."); } if (obj.isAbstract()){ throw new ClassConstraintException("Class or interface initialization method '"+tostring(obj)+"' must not be abstract. This contradicts the Java Language Specification, Second Edition (which omits this constraint) but is common practice of existing verifiers."); } } if ((obj.getAccessFlags() & ~(ACC_PUBLIC|ACC_PRIVATE|ACC_PROTECTED|ACC_STATIC|ACC_FINAL|ACC_SYNCHRONIZED|ACC_NATIVE|ACC_ABSTRACT|ACC_STRICT)) > 0){ addMessage("Method '"+tostring(obj)+"' has access flag(s) other than ACC_PUBLIC, ACC_PRIVATE, ACC_PROTECTED, ACC_STATIC, ACC_FINAL, ACC_SYNCHRONIZED, ACC_NATIVE, ACC_ABSTRACT, ACC_STRICT set (ignored)."); } String nameanddesc = (name+sig); if (method_names_and_desc.contains(nameanddesc)){ throw new ClassConstraintException("No two methods (like '"+tostring(obj)+"') are allowed have same names and desciptors!"); } method_names_and_desc.add(nameanddesc); Attribute[] atts = obj.getAttributes(); int num_code_atts = 0; for (int i=0; i<atts.length; i++){ if ((! (atts[i] instanceof Code)) && (! (atts[i] instanceof ExceptionTable)) && (! (atts[i] instanceof Synthetic)) && (! (atts[i] instanceof Deprecated))){ addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of Method '"+tostring(obj)+"' is unknown and will therefore be ignored."); } if ((! (atts[i] instanceof Code)) && (! (atts[i] instanceof ExceptionTable))){ addMessage("Attribute '"+tostring(atts[i])+"' as an attribute of Method '"+tostring(obj)+"' is neither Code nor Exceptions and is therefore only of use for debuggers and such."); } if ((atts[i] instanceof Code) && (obj.isNative() || obj.isAbstract())){ throw new ClassConstraintException("Native or abstract methods like '"+tostring(obj)+"' must not have a Code attribute like '"+tostring(atts[i])+"'."); //vmspec2 page120, 4.7.3 } if (atts[i] instanceof Code) num_code_atts++; } if ( !obj.isNative() && !obj.isAbstract() && num_code_atts != 1){ throw new ClassConstraintException("Non-native, non-abstract methods like '"+tostring(obj)+"' must have exactly one Code attribute (found: "+num_code_atts+")."); } } /////////////////////////////////////////////////////// // ClassFile-structure-ATTRIBUTES (vmspec2 4.1, 4.7) // /////////////////////////////////////////////////////// public void visitSourceFile(SourceFile obj){//vmspec2 4.7.7 // zero or one SourceFile attr per ClassFile: see visitJavaClass() checkIndex(obj, obj.getNameIndex(), CONST_Utf8); String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); if (! name.equals("SourceFile")){ throw new ClassConstraintException("The SourceFile attribute '"+tostring(obj)+"' is not correctly named 'SourceFile' but '"+name+"'."); } checkIndex(obj, obj.getSourceFileIndex(), CONST_Utf8); String sourcefilename = ((ConstantUtf8) cp.getConstant(obj.getSourceFileIndex())).getBytes(); //==obj.getSourceFileName() ? String sourcefilenamelc = sourcefilename.toLowerCase(); if ( (sourcefilename.indexOf('/') != -1) || (sourcefilename.indexOf('\\') != -1) || (sourcefilename.indexOf(':') != -1) || (sourcefilenamelc.lastIndexOf(".java") == -1) ){ addMessage("SourceFile attribute '"+tostring(obj)+"' has a funny name: remember not to confuse certain parsers working on javap's output. Also, this name ('"+sourcefilename+"') is considered an unqualified (simple) file name only."); } } public void visitDeprecated(Deprecated obj){//vmspec2 4.7.10 checkIndex(obj, obj.getNameIndex(), CONST_Utf8); String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); if (! name.equals("Deprecated")){ throw new ClassConstraintException("The Deprecated attribute '"+tostring(obj)+"' is not correctly named 'Deprecated' but '"+name+"'."); } } public void visitSynthetic(Synthetic obj){//vmspec2 4.7.6 checkIndex(obj, obj.getNameIndex(), CONST_Utf8); String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); if (! name.equals("Synthetic")){ throw new ClassConstraintException("The Synthetic attribute '"+tostring(obj)+"' is not correctly named 'Synthetic' but '"+name+"'."); } } public void visitInnerClasses(InnerClasses obj){//vmspec2 4.7.5 // exactly one InnerClasses attr per ClassFile if some inner class is refernced: see visitJavaClass() checkIndex(obj, obj.getNameIndex(), CONST_Utf8); String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); if (! name.equals("InnerClasses")){ throw new ClassConstraintException("The InnerClasses attribute '"+tostring(obj)+"' is not correctly named 'InnerClasses' but '"+name+"'."); } InnerClass[] ics = obj.getInnerClasses(); for (int i=0; i<ics.length; i++){ checkIndex(obj, ics[i].getInnerClassIndex(), CONST_Class); int outer_idx = ics[i].getOuterClassIndex(); if (outer_idx != 0){ checkIndex(obj, outer_idx, CONST_Class); } int innername_idx = ics[i].getInnerNameIndex(); if (innername_idx != 0){ checkIndex(obj, innername_idx, CONST_Utf8); } int acc = ics[i].getInnerAccessFlags(); acc = acc & (~ (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT)); if (acc != 0){ addMessage("Unknown access flag for inner class '"+tostring(ics[i])+"' set (InnerClasses attribute '"+tostring(obj)+"')."); } } // Semantical consistency is not yet checked by Sun, see vmspec2 4.7.5. // [marked TODO in JustIce] } //////////////////////////////////////////////////////// // field_info-structure-ATTRIBUTES (vmspec2 4.5, 4.7) // //////////////////////////////////////////////////////// public void visitConstantValue(ConstantValue obj){//vmspec2 4.7.2 // Despite its name, this really is an Attribute, // not a constant! checkIndex(obj, obj.getNameIndex(), CONST_Utf8); String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); if (! name.equals("ConstantValue")){ throw new ClassConstraintException("The ConstantValue attribute '"+tostring(obj)+"' is not correctly named 'ConstantValue' but '"+name+"'."); } Object pred = carrier.predecessor(); if (pred instanceof Field){ //ConstantValue attributes are quite senseless if the predecessor is not a field. Field f = (Field) pred; // Field constraints have been checked before -- so we are safe using their type information. Type field_type = Type.getType(((ConstantUtf8) (cp.getConstant(f.getSignatureIndex()))).getBytes()); int index = obj.getConstantValueIndex(); if ((index < 0) || (index >= cplen)){ throw new ClassConstraintException("Invalid index '"+index+"' used by '"+tostring(obj)+"'."); } Constant c = cp.getConstant(index); if (CONST_Long.isInstance(c) && field_type.equals(Type.LONG)){ return; } if (CONST_Float.isInstance(c) && field_type.equals(Type.FLOAT)){ return; } if (CONST_Double.isInstance(c) && field_type.equals(Type.DOUBLE)){ return; } if (CONST_Integer.isInstance(c) && (field_type.equals(Type.INT) || field_type.equals(Type.SHORT) || field_type.equals(Type.CHAR) || field_type.equals(Type.BYTE) || field_type.equals(Type.BOOLEAN))){ return; } if (CONST_String.isInstance(c) && field_type.equals(Type.STRING)){ return; } throw new ClassConstraintException("Illegal type of ConstantValue '"+obj+"' embedding Constant '"+c+"'. It is referenced by field '"+tostring(f)+"' expecting a different type: '"+field_type+"'."); } } // SYNTHETIC: see above // DEPRECATED: see above ///////////////////////////////////////////////////////// // method_info-structure-ATTRIBUTES (vmspec2 4.6, 4.7) // ///////////////////////////////////////////////////////// public void visitCode(Code obj){//vmspec2 4.7.3 // No code attribute allowed for native or abstract methods: see visitMethod(Method). // Code array constraints are checked in Pass3 (3a and 3b). checkIndex(obj, obj.getNameIndex(), CONST_Utf8); String name = ((ConstantUtf8) cp.getConstant(obj.getNameIndex())).getBytes(); if (! name.equals("Code")){ throw new ClassConstraintException("The Code attribute '"+tostring(obj)+"' is not correctly named 'Code' but '"+name+"'."); } Method m = null; // satisfy compiler if (!(carrier.predecessor() instanceof Method)){ addMessage("Code attribute '"+tostring(obj)+"' is not declared in a method_info structure but in '"+carrier.predecessor()+"'. Ignored."); return; } else{ m = (Method) carrier.predecessor(); // we can assume this method was visited before; // i.e. the data consistency was verified. } if (obj.getCode().length == 0){ throw new ClassConstraintException("Code array of Code attribute '"+tostring(obj)+"' (method '"+m+"') must not be empty."); } //In JustIce, the check for correct offsets into the code array is delayed to Pass 3a. CodeException[] exc_table = obj.getExceptionTable(); for (int i=0; i<exc_table.length; i++){ int exc_index = exc_table[i].getCatchType(); if (exc_index != 0){ // if 0, it catches all Throwables checkIndex(obj, exc_index, CONST_Class); ConstantClass cc = (ConstantClass) (cp.getConstant(exc_index)); 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('/','.'); Verifier v = VerifierFactory.getVerifier(cname); VerificationResult vr = v.doPass1(); if (vr != VerificationResult.VR_OK){ throw new ClassConstraintException("Code attribute '"+tostring(obj)+"' (method '"+m+"') has an exception_table entry '"+tostring(exc_table[i])+"' that 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("Code attribute '"+tostring(obj)+"' (method '"+m+"') has an exception_table entry '"+tostring(exc_table[i])+"' that 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("Code attribute '"+tostring(obj)+"' (method '"+m+"') has an exception_table entry '"+tostring(exc_table[i])+"' that references '"+cname+"' as an Exception but it is not a subclass of '"+t.getClassName()+"'."); } } } // Create object for local variables information // This is highly unelegant due to usage of the Visitor pattern. // TODO: rework it. int method_number = -1; Method[] ms = Repository.lookupClass(myOwner.getClassName()).getMethods(); for (int mn=0; mn<ms.length; mn++){ if (m == ms[mn]){ method_number = mn; break; } } if (method_number < 0){ // Mmmmh. Can we be sure BCEL does not sometimes instantiate new objects? throw new AssertionViolatedException("Could not find a known BCEL Method object in the corresponding BCEL JavaClass object."); } localVariablesInfos[method_number] = new LocalVariablesInfo(obj.getMaxLocals()); int num_of_lvt_attribs = 0; // Now iterate through the attributes the Code attribute has. Attribute[] atts = obj.getAttributes(); for (int a=0; a<atts.length; a++){ if ((! (atts[a] instanceof LineNumberTable)) && (! (atts[a] instanceof LocalVariableTable))){ addMessage("Attribute '"+tostring(atts[a])+"' as an attribute of Code attribute '"+tostring(obj)+"' (method '"+m+"') is unknown and will therefore be ignored."); } else{// LineNumberTable or LocalVariableTable addMessage("Attribute '"+tostring(atts[a])+"' as an attribute of Code attribute '"+tostring(obj)+"' (method '"+m+"') will effectively be ignored and is only useful for debuggers and such."); } //LocalVariableTable check (partially delayed to Pass3a). //Here because its easier to collect the information of the //(possibly more than one) LocalVariableTables belonging to //one certain Code attribute. if (atts[a] instanceof LocalVariableTable){ // checks conforming to vmspec2 4.7.9 LocalVariableTable lvt = (LocalVariableTable) atts[a]; checkIndex(lvt, lvt.getNameIndex(), CONST_Utf8); String lvtname = ((ConstantUtf8) cp.getConstant(lvt.getNameIndex())).getBytes(); if (! lvtname.equals("LocalVariableTable")){ throw new ClassConstraintException("The LocalVariableTable attribute '"+tostring(lvt)+"' is not correctly named 'LocalVariableTable' but '"+lvtname+"'."); } Code code = obj; int max_locals = code.getMaxLocals(); //In JustIce, the check for correct offsets into the code array is delayed to Pass 3a. LocalVariable[] localvariables = lvt.getLocalVariableTable(); for (int i=0; i<localvariables.length; i++){ checkIndex(lvt, localvariables[i].getNameIndex(), CONST_Utf8); String localname = ((ConstantUtf8) cp.getConstant(localvariables[i].getNameIndex())).getBytes(); if (!validJavaIdentifier(localname)){ throw new ClassConstraintException("LocalVariableTable '"+tostring(lvt)+"' references a local variable by the name '"+localname+"' which is not a legal Java simple name."); } checkIndex(lvt, localvariables[i].getSignatureIndex(), CONST_Utf8); String localsig = ((ConstantUtf8) (cp.getConstant(localvariables[i].getSignatureIndex()))).getBytes(); // Local signature(=descriptor) Type t; try{ t = Type.getType(localsig); } catch (ClassFormatError cfe){ // sometimes BCEL is a little harsh describing exceptional situations. throw new ClassConstraintException("Illegal descriptor (==signature) '"+localsig+"' used by LocalVariable '"+tostring(localvariables[i])+"' referenced by '"+tostring(lvt)+"'."); } int localindex = localvariables[i].getIndex();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -