📄 pass2verifier.java
字号:
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.");
}
}
}
// 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;
//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)+"'.");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -