📄 verify.c
字号:
if (checkMethodStaticConstraints(method, einfo) == false) { /* something else is wrong...exception raised elsewhere */ return(false); } } } else { /********************************************************* * 2b: check that final methods are not overridden *********************************************************/ Hjava_lang_Class *superclass; Method* curMethod; Method* method; int n, m; for (n = CLASS_NMETHODS(class), curMethod = CLASS_METHODS(class); n > 0; --n, ++curMethod) { /* check static constraints on each method */ if (METHOD_IS_CONSTRUCTOR(curMethod) && checkConstructor(curMethod, einfo) == false) { return(false); } else if (checkMethodStaticConstraints(curMethod, einfo) == false) { return(false); } } /* cycle through superclass hiarchy and make sure final methods aren't overriden */ for (superclass = class->superclass; superclass != NULL; superclass = superclass->superclass) { /* cycle through methods in current super class */ for (m = CLASS_NMETHODS(superclass), method = CLASS_METHODS(superclass); m > 0; --m, ++method) { if (METHOD_IS_FINAL(method) && !METHOD_IS_PRIVATE(method) && /* the following exceptions come from testing against Sun's JVM behavior */ (strcmp(init_name->data, METHOD_NAMED(method)) && strcmp("this", METHOD_NAMED(method)))) { /* make sure the method in question was not overriden in the current class */ for (n = CLASS_NMETHODS(class), curMethod = CLASS_METHODS(class); n > 0; --n, ++curMethod) { /* TODO: we should really put all the methods of class into a hash table * that we can access through name and signature. this would make * this check more efficient (is this done in the interpretter? if so * we may think about setting up the hashes here and just keeping them * around for later). */ if (utf8ConstEqual(curMethod->name, method->name) && utf8ConstEqual(METHOD_SIG(curMethod), METHOD_SIG(method))) { postExceptionMessage(einfo, JAVA_LANG(VerifyError), "final method \"%s\" declared in class \"%s\" is overriden in class \"%s\"", METHOD_NAMED(method), CLASS_CNAME(class->superclass), CLASS_CNAME(class)); return(false); } } } } } } } /********************************************************* * 3 - Check class constant pool is consistent * * This is the only section of pass 2 that was available * under Transvirtual, though even this has been modified. *********************************************************/ /* error message for step 3 */#define POOLERROR \ postExceptionMessage(einfo, JAVA_LANG(ClassFormatError), "malformed constant pool in class \"%s\"", CLASS_CNAME(class)); \ return (false) pool = CLASS_CONSTANTS(class); /* Constant pool loaded - check it's integrity. */ for (idx = 1; idx < pool->size; idx++) { switch (pool->tags[idx]) { case CONSTANT_Fieldref: case CONSTANT_Methodref: case CONSTANT_InterfaceMethodref: tag = CONST_TAG(FIELDREF_CLASS(idx, pool), pool); if (tag != CONSTANT_Class && tag != CONSTANT_ResolvedClass) { POOLERROR; } if (CONST_TAG(FIELDREF_NAMEANDTYPE(idx, pool), pool) != CONSTANT_NameAndType) { POOLERROR; } break; case CONSTANT_NameAndType: if (CONST_TAG(NAMEANDTYPE_NAME(idx, pool), pool) != CONSTANT_Utf8) { POOLERROR; } if (CONST_TAG(NAMEANDTYPE_SIGNATURE(idx, pool), pool) != CONSTANT_Utf8) { POOLERROR; } break; /* the following tags are always legal, so no furthur checks need be performed */ case CONSTANT_Long: case CONSTANT_Double: idx++; case CONSTANT_Integer: case CONSTANT_Float: case CONSTANT_Utf8: case CONSTANT_ResolvedString: case CONSTANT_ResolvedClass: /* CONSTANT_Class and CONSTANT_String * have already been re-written to avoid the * extra indirection added by Java. This is to fit * with the precompiled format. Here we will not * get an error. */ case CONSTANT_Class: case CONSTANT_String: break; default: /* undefined tag */ POOLERROR; break; } }#undef POOLERROR DBG(VERIFY2, printConstantPool(class)); /************************************************************** * 4 - ensure that all field and method references in * constant pool have valid names, classes, and type * descriptor * * From the JVM spec pp.141-2: * Note that when it looks at field and method references, * this pass does not check to make sure that the given * field or method actually exists in the given class, nor * does it check that the type descriptors given refer to * real classes. It checks only that these items are well * formed. **************************************************************/ /* Constant pool loaded - check the integrity of the type references */ pool = CLASS_CONSTANTS(class); for (idx = 1; idx < pool->size; idx++) { switch (pool->tags[idx]) { case CONSTANT_Long: case CONSTANT_Double: idx++; case CONSTANT_Integer: case CONSTANT_Float: case CONSTANT_Utf8: case CONSTANT_ResolvedString: case CONSTANT_ResolvedClass: case CONSTANT_Class: case CONSTANT_String: case CONSTANT_NameAndType: break; case CONSTANT_Fieldref: if (!parseFieldTypeDescriptor(FIELDREF_SIGD(idx, pool))) { postExceptionMessage(einfo, JAVA_LANG(ClassFormatError), "malformed field reference type descriptor, \"%s\", in class \"%s\"", CONST_UTF2CHAR(FIELDREF_TYPE(idx, pool), pool), CLASS_CNAME(class)); return(false); } break; case CONSTANT_Methodref: if (!parseMethodTypeDescriptor(METHODREF_SIGD(idx, pool))) { postExceptionMessage(einfo, JAVA_LANG(ClassFormatError), "malformed method reference type descriptor, \"%s\", in class \"%s\"", CONST_UTF2CHAR(METHODREF_SIGNATURE(idx, pool), pool), CLASS_CNAME(class)); return(false); } break; case CONSTANT_InterfaceMethodref: if (!parseMethodTypeDescriptor(INTERFACEMETHODREF_SIGD(idx, pool))) { postExceptionMessage(einfo, JAVA_LANG(ClassFormatError), "malformed interface method reference type descriptor, \"%s\", in class \"%s\"", CONST_UTF2CHAR(INTERFACEMETHODREF_SIGNATURE(idx, pool), pool), CLASS_CNAME(class)); return(false); } break; default: /* we'll never get here, because of pass 3 */ postExceptionMessage(einfo, JAVA_LANG(InternalError), "step 4 of pass 2 verification has screwed up while processing class \"%s\"", CLASS_CNAME(class)); return(false); } } return (true);}staticboolcheckField(Field *field, errorInfo *einfo){ bool retval = true; char *reason; if( (reason = checkAccessFlags(CLASS_IS_INTERFACE(field->clazz) ? ACC_TYPE_INTERFACE_FIELD : ACC_TYPE_FIELD, field->accflags)) != NULL ) { postExceptionMessage(einfo, JAVA_LANG(ClassFormatError), "(class: %s, field: %s) %s", CLASS_CNAME(field->clazz), field->name->data, reason); retval = false; } return( retval );}/* * makes sure a constructor's flags are valid. */staticboolcheckConstructor(Method* method, errorInfo* einfo){ if (METHOD_IS_STATIC(method)) { postExceptionMessage(einfo, JAVA_LANG(ClassFormatError), "class %s: constructor cannot be static", CLASS_CNAME(method->class)); return false; } else if (METHOD_IS_FINAL(method)) { postExceptionMessage(einfo, JAVA_LANG(ClassFormatError), "class %s: constructor cannot be final", CLASS_CNAME(method->class)); return false; } else if (!isMethodVoid(method)) { postExceptionMessage(einfo, JAVA_LANG(ClassFormatError), "class %s: constructor does not have void return type", CLASS_CNAME(method->class)); return false; } else if (checkMethodStaticConstraints(method, einfo) == false) { return false; } return(true);}/* * ensures that all access flags are legal (more specifically, that the combination * of access flags in a method is legal). * * also checks code-length constraints of the method. */staticboolcheckMethodStaticConstraints(Method* method, errorInfo* einfo){ if (METHOD_IS_PUBLIC(method)) { if (METHOD_IS_PROTECTED(method)) { postExceptionMessage(einfo, JAVA_LANG(ClassFormatError), "%s.%s: method cannot be both public and protected", CLASS_CNAME(method->class), METHOD_NAMED(method)); return(false); } else if(METHOD_IS_PRIVATE(method)) { postExceptionMessage(einfo, JAVA_LANG(ClassFormatError), "%s.%s: method cannot be both public and private", CLASS_CNAME(method->class), METHOD_NAMED(method)); return(false); } } else if (METHOD_IS_PROTECTED(method) && METHOD_IS_PRIVATE(method)) { postExceptionMessage(einfo, JAVA_LANG(ClassFormatError), "%s.%s: method cannot be both protected and private", CLASS_CNAME(method->class), METHOD_NAMED(method)); return(false); } if (METHOD_IS_ABSTRACT(method)) { if (checkAbstractMethod(method, einfo) == false) { return(false); } } else if (!METHOD_IS_NATIVE(method)) { /* code length static constraints */ if (METHOD_BYTECODE_LEN(method) == 0) { postExceptionMessage(einfo, JAVA_LANG(ClassFormatError), "%s.%s: method's code length cannot be zero", CLASS_CNAME(method->class), METHOD_NAMED(method)); return(false); } else if (METHOD_BYTECODE_LEN(method) >= 65536) { postExceptionMessage(einfo, JAVA_LANG(ClassFormatError), "%s.%s: method's code length must be less than 65536 bytes", CLASS_CNAME(method->class), METHOD_NAMED(method)); return(false); } } return(true);}/* * Given a method with its ACC_ABSTRACT flag set, this checks the the rest of the access flags * are set appropriately. that is, it cannot be final, native, private, static, strictfp, or synchronized. * * also, we check that an abstract method doesn't have a code attribute. */staticboolcheckAbstractMethod(Method* method, errorInfo* einfo){#define ABSTRACT_METHOD_ERROR(_MSG) \ postExceptionMessage(einfo, JAVA_LANG(ClassFormatError), \ "in method \"%s.%s\": abstract methods cannot be %s", \ CLASS_CNAME(method->class), \ METHOD_NAMED(method), _MSG); \ return(false) #ifdef ABSTRACT_METHOD_VS_ABSTRACT_CLASS /* This is commented out because Sun's verifier doesn't care if an abstract method * is in an abstract class. */ /* ensure that only abstract classes may have abstract methods */ if (!(CLASS_IS_INTERFACE(method->class) || CLASS_IS_ABSTRACT(method->class))) { postExceptionMessage(einfo, JAVA_LANG(ClassFormatError), "in method \"%s.%s\": only abstract classes may have abstract methods", CLASS_CNAME(method->class), METHOD_NAMED(method)); return(false); }#endif /* ABSTRACT_METHOD_VS_ABSTRACT_CLASS */ /* constructors cannot be abstract */ if (METHOD_IS_CONSTRUCTOR(method)) { if (CLASS_IS_INTERFACE(method->class)) { postExceptionMessage(einfo, JAVA_LANG(ClassFormatError), "in method \"%s.%s\": an interface cannot have a constructor <init>", CLASS_CNAME(method->class), METHOD_NAMED(method)); return(false); } else { postExceptionMessage(einfo, JAVA_LANG(ClassFormatError), "in method \"%s.%s\": constructors cannot be abstract", CLASS_CNAME(method->class), METHOD_NAMED(method)); return(false); } } /* ensure the abstract method has no code */ if (METHOD_BYTECODE_LEN(method) > 0) { postExceptionMessage(einfo, JAVA_LANG(ClassFormatError), "in method \"%s.%s\": abstract methods cannot have a Code attribute", CLASS_CNAME(method->class), METHOD_NAMED(method)); return(false); } /* enforce access flag rules of the JVML spec. for abstract methods */ if (METHOD_IS_PRIVATE(method)) { ABSTRACT_METHOD_ERROR("private"); } else if (METHOD_IS_FINAL(method)) { ABSTRACT_METHOD_ERROR("final"); } else if (METHOD_IS_NATIVE(method)) { ABSTRACT_METHOD_ERROR("native"); } else if (METHOD_IS_STATIC(method)) { ABSTRACT_METHOD_ERROR("static"); } else if (METHOD_IS_STRICT(method)) { ABSTRACT_METHOD_ERROR("strictfp"); } /* not enforced by Sun's verifier * else if (METHOD_IS_SYNCHRONISED(method)) { ABSTRACT_METHOD_ERROR("synchronized"); } */ return(true); #undef ABSTRACT_METHOD_ERROR}/************************************************************************************ * Pass 3 Verification * * Pass 3 of verification is broken up into two distinct passes. The first, 3a, * checks static constraints of the bytecode (detailed on p. 134 of the JVML Spec 2). * The second, 3b, performs data-flow analysis on the bytecode, which checks structural * constraints and does type checking. * * NOTE: according to p.171 of JVML Spec 2, "Performing verification at link time * is attractive in that the checks are performed just once, substantially * reducing the amount of work that must be done at run time. Other * implementation strategies are possible, provided that they comply with * The Java Language Specification and The Java Virtual Machine Specification." * * In other words, we can perform pass 3 verification whenever convenient, and * not necessarily at link time. This could provide for optimizations in the * future, as verification generates a lot of information that is useful to * the JIT compilers. At the moment, this same information is generated by
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -