📄 verify2.c
字号:
/* * verify2.c * * Copyright 2004, 2005 * Kaffe.org contributors. See ChangeLog for details. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file. * * * verify2() was originally created by someone in Transvirtual Technologies. however, * it did almost nothing (only a shrivel of the stuff needed by pass 2... * specifically part 3 of of pass 2, which has been modified), * so questions regarding pass 2 should be sent to: * Rob Gonzalez <rob@kaffe.org> */#include "config.h"#ifdef HAVE_STRING_H#include <string.h>#endif#include "access.h"#include "baseClasses.h"#include "classMethod.h"#include "errors.h"#include "gtypes.h"#include "utf8const.h"#include "verify.h"#include "verify-debug.h"/********************************************************************************* * Pass 2 Verification *********************************************************************************//* Helper function for pool errors */static inlineboolpoolError(Hjava_lang_Class* class, errorInfo *einfo){ postExceptionMessage(einfo, JAVA_LANG(ClassFormatError), "malformed constant pool in class \"%s\"", CLASS_CNAME(class)); return (false);}staticboolcheckField(Field *field, errorInfo *einfo){ const char *reason = checkAccessFlags(CLASS_IS_INTERFACE(field->clazz) ? ACC_TYPE_INTERFACE_FIELD : ACC_TYPE_FIELD, field->accflags); if (reason) { postExceptionMessage(einfo, JAVA_LANG(ClassFormatError), "(class: %s, field: %s) %s", CLASS_CNAME(field->clazz), field->name->data, reason); return false; } return true;}/* perhaps this should go in classMethod.[ch]... */static bool isMethodVoid(Method* method){ char* sig = (char*)method->parsed_sig->signature->data; int i = strlen(sig); return (i > 2) && (sig[i-2] == ')' && sig[i-1] == 'V');}static inlineboolabstractMethodError(Method* method, errorInfo* einfo, const char * 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);}/* * 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){ #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)) { return abstractMethodError(method, einfo, "private"); } else if (METHOD_IS_FINAL(method)) { return abstractMethodError(method, einfo, "final"); } else if (METHOD_IS_NATIVE(method)) { return abstractMethodError(method, einfo, "native"); } else if (METHOD_IS_STATIC(method)) { return abstractMethodError(method, einfo, "static"); } else if (METHOD_IS_STRICT(method)) { return abstractMethodError(method, einfo, "strictfp"); } /* not enforced by Sun's verifier * else if (METHOD_IS_SYNCHRONISED(method)) { return abstractMethodError(method, einfo, "synchronized"); } */ 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);}/* * 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);}/* * Verify pass 2: Check the internal consistency of the class file * but do not check the bytecode. If at any point we find an error in the * class file format, we abort and throw a ClassFormatError or VerifyError * (depending on what the Sun Java VM would throw given the specific error). * * According to the JVML spec for Java 2, this should do the following: * 1. ensure that every class (except java/lang/Object) has a direct superclass * * 2. a. ensure that final classes are not subclassed * b. ensure that final methods are not overriden * * 3. ensure that constant pool satisfies the documented static constraints * - i.e. each CONSTANT_Class_info structure in constant pool contains in its * name_index item a valid constant pool index for a CONSTANT_Utf8_info structure, * etc. * * 4. ensure that all field references and method references in the constant pool have * (this is basically parsing type signatures for validity): * - valid names * - valid classes * - a valid type desriptor * * However, the JVML spec also specifies a bunch of other rules that make sense to be * checked here (i.e. interfaces must be abstract) */boolverify2(Hjava_lang_Class* class, errorInfo *einfo){ constants* pool; uint32 idx; int tag; if (isTrustedClass(class)) return(true); DBG(VERIFY2, dprintf("\nPass 2 Verifying class %s\n", CLASS_CNAME(class)); ); #ifdef UNENFORCED_INTERFACE_RESTRICTIONS /* this is commented out because Sun's Java runtime environment doesn't enforce the restrictions * placed upon interfaces by the specification. * GJC also doesn't follow this! */ if (CLASS_IS_INTERFACE(class)) { /* JVML spec p. 96: if a class has ACC_INTERFACE flag set, it must also have * ( ACC_ABSTRACT set and may have ACC_PUBLIC set. it may not have any other flags * (in the given table) set. */ if (!CLASS_IS_ABSTRACT(class)) { postExceptionMessage(einfo, JAVA_LANG(ClassFormatError), "interfaces must have their abstract flag set (in interface \"%s\")",
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -