Return-Path: Delivered-To: apmail-harmony-commits-archive@www.apache.org Received: (qmail 22290 invoked from network); 26 Dec 2006 00:08:20 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 26 Dec 2006 00:08:20 -0000 Received: (qmail 71731 invoked by uid 500); 26 Dec 2006 00:08:27 -0000 Delivered-To: apmail-harmony-commits-archive@harmony.apache.org Received: (qmail 71698 invoked by uid 500); 26 Dec 2006 00:08:27 -0000 Mailing-List: contact commits-help@harmony.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@harmony.apache.org Delivered-To: mailing list commits@harmony.apache.org Received: (qmail 71679 invoked by uid 99); 26 Dec 2006 00:08:27 -0000 Received: from herse.apache.org (HELO herse.apache.org) (140.211.11.133) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 25 Dec 2006 16:08:27 -0800 X-ASF-Spam-Status: No, hits=-9.4 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO eris.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 25 Dec 2006 16:08:18 -0800 Received: by eris.apache.org (Postfix, from userid 65534) id AB2971A981A; Mon, 25 Dec 2006 16:07:26 -0800 (PST) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Subject: svn commit: r490202 - in /harmony/enhanced/drlvm/trunk/vm/vmcore: include/ src/class_support/ src/init/ src/kernel_classes/native/ src/reflection/ Date: Tue, 26 Dec 2006 00:07:26 -0000 To: commits@harmony.apache.org From: gshimansky@apache.org X-Mailer: svnmailer-1.1.0 Message-Id: <20061226000726.AB2971A981A@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: gshimansky Date: Mon Dec 25 16:07:25 2006 New Revision: 490202 URL: http://svn.apache.org/viewvc?view=rev&rev=490202 Log: Applied HARMONY-2872 [drlvm][classloader] Improved class file format parser Tests passed on Ubuntu6 x86, WindowsXP x86 and SuSE9 x86_64 Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/include/Class.h harmony/enhanced/drlvm/trunk/vm/vmcore/include/annotations.h harmony/enhanced/drlvm/trunk/vm/vmcore/include/class_member.h harmony/enhanced/drlvm/trunk/vm/vmcore/include/environment.h harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/C_Interface.cpp harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/Class.cpp harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/Class_File_Loader.cpp harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/Environment.cpp harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/Resolve.cpp harmony/enhanced/drlvm/trunk/vm/vmcore/src/init/parse_arguments.cpp harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMGenericsAndAnnotations.cpp harmony/enhanced/drlvm/trunk/vm/vmcore/src/reflection/annotations.cpp Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/include/Class.h URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/include/Class.h?view=diff&rev=490202&r1=490201&r2=490202 ============================================================================== --- harmony/enhanced/drlvm/trunk/vm/vmcore/include/Class.h (original) +++ harmony/enhanced/drlvm/trunk/vm/vmcore/include/Class.h Mon Dec 25 16:07:25 2006 @@ -161,7 +161,7 @@ enum ConstPoolTags { /** pointer to the tags array.*/ CONSTANT_Tags = 0, - /** The rest of tag values are taken from + /** The next 11 tag values are taken from * * The Java Virtual Machine Specification, Chapter 4, The Constant * Pool section.*/ @@ -176,6 +176,9 @@ CONSTANT_Methodref = 10, CONSTANT_InterfaceMethodref = 11, CONSTANT_NameAndType = 12, + CONSTANT_Last = CONSTANT_NameAndType, + /** used to mark second entry of Long and Double*/ + CONSTANT_UnusedEntry = CONSTANT_Last + 1, }; @@ -1001,6 +1004,9 @@ // annotations for this class AnnotationTable* m_annotations; + //invisible annotations for this class + AnnotationTable* m_invisible_annotations; + // thread, which currently executes VM_thread* m_initializing_thread; @@ -1340,7 +1346,11 @@ /** Gets a collection of annotations. * @return A collection of annotations.*/ AnnotationTable* get_annotations() const { return m_annotations; } - + /** Gets a collection of invisible annotations. + * @return A collection of invisible annotations.*/ + AnnotationTable* get_invisible_annotations() const { + return m_invisible_annotations; + } /** Gets a class instance size. * @return A size of the allocated instance in bytes.*/ unsigned int get_allocated_size() const { return m_allocated_size; } Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/include/annotations.h URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/include/annotations.h?view=diff&rev=490202&r1=490201&r2=490202 ============================================================================== --- harmony/enhanced/drlvm/trunk/vm/vmcore/include/annotations.h (original) +++ harmony/enhanced/drlvm/trunk/vm/vmcore/include/annotations.h Mon Dec 25 16:07:25 2006 @@ -29,10 +29,11 @@ struct Annotation; struct AnnotationValue; -// Returns array of declared annotations. +// Returns array of declared visible annotations +// and in case -Xinvisible command line flag is set also returns array of invisible annotations. // Returns zero-sized array if there are no annotations. // May raise an exception, in this case returns null. -jobjectArray get_annotations(JNIEnv* jenv, AnnotationTable* table, Class* clss); +jobjectArray get_annotations(JNIEnv* jenv, AnnotationTable* table, AnnotationTable *inv_table, Class* clss); // Returns resolved annotation or null if resolution failed. // If the cause parameter is not null, resolution error is assigned to it for upstream processing; Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/include/class_member.h URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/include/class_member.h?view=diff&rev=490202&r1=490201&r2=490202 ============================================================================== --- harmony/enhanced/drlvm/trunk/vm/vmcore/include/class_member.h (original) +++ harmony/enhanced/drlvm/trunk/vm/vmcore/include/class_member.h Mon Dec 25 16:07:25 2006 @@ -86,6 +86,9 @@ String *get_signature() const {return _signature;} AnnotationTable* get_declared_annotations() const {return _annotations;} + AnnotationTable* get_declared_invisible_annotations() const { + return _invisible_annotations; + } friend void assign_offsets_to_class_fields(Class *); friend void add_new_fake_method(Class *clss, Class *example, unsigned *next); @@ -109,6 +112,7 @@ #endif _synthetic = _deprecated = false; _annotations = NULL; + _invisible_annotations = NULL; _signature = NULL; } @@ -122,6 +126,7 @@ bool _synthetic; bool _deprecated; AnnotationTable* _annotations; + AnnotationTable* _invisible_annotations; uint16 _access_flags; String* _name; @@ -208,7 +213,7 @@ unsigned is_transient() {return (_access_flags&ACC_TRANSIENT);} bool is_enum() {return (_access_flags&ACC_ENUM)?true:false;} - bool parse(Class* clss, ByteReader& cfs); + bool parse(Global_Env& env, Class* clss, ByteReader& cfs); unsigned calculate_size(); @@ -647,11 +652,22 @@ AnnotationTable * get_param_annotations(unsigned index) { return index < _num_param_annotations ? _param_annotations[index] : NULL; } + unsigned get_num_invisible_param_annotations() { + return _num_invisible_param_annotations; + } + AnnotationTable * get_invisible_param_annotations(unsigned index) { + return index < _num_invisible_param_annotations ? + _invisible_param_annotations[index] : NULL; + } + AnnotationValue * get_default_value() {return _default_value; } private: uint8 _num_param_annotations; AnnotationTable ** _param_annotations; + uint8 _num_invisible_param_annotations; + AnnotationTable ** _invisible_param_annotations; + AnnotationValue * _default_value; unsigned _index; // index in method table Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/include/environment.h URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/include/environment.h?view=diff&rev=490202&r1=490201&r2=490202 ============================================================================== --- harmony/enhanced/drlvm/trunk/vm/vmcore/include/environment.h (original) +++ harmony/enhanced/drlvm/trunk/vm/vmcore/include/environment.h Mon Dec 25 16:07:25 2006 @@ -74,7 +74,8 @@ size_t system_page_size; // system page size according to use_large_pages value bool verify_all; // psrebriy 20050815 Verify all classes including loaded by bootstrap class loader bool pin_interned_strings; // if true, interned strings are never moved - + bool retain_invisible_annotations; // retain InvisibleAnnotation and InvisibleParameterAnnotation + Lock_Manager *p_jit_a_method_lock; Lock_Manager *p_vtable_patch_lock; Lock_Manager *p_meth_addr_table_lock; Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/C_Interface.cpp URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/C_Interface.cpp?view=diff&rev=490202&r1=490201&r2=490202 ============================================================================== --- harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/C_Interface.cpp (original) +++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/C_Interface.cpp Mon Dec 25 16:07:25 2006 @@ -843,6 +843,14 @@ case CONSTANT_Class: jt = JAVA_TYPE_CLASS; break; + case CONSTANT_UnusedEntry: + if(cp.get_tag(index - 1) == CONSTANT_Double) { + jt = JAVA_TYPE_DOUBLE; + break; + } else if(cp.get_tag(index - 1) == CONSTANT_Long) { + jt = JAVA_TYPE_LONG; + break; + } default: DIE("non-constant type is requested from constant pool : " << cp.get_tag(index)); } Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/Class.cpp URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/Class.cpp?view=diff&rev=490202&r1=490201&r2=490202 ============================================================================== --- harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/Class.cpp (original) +++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/Class.cpp Mon Dec 25 16:07:25 2006 @@ -627,7 +627,9 @@ _line_number_table = NULL; _local_vars_table = NULL; _num_param_annotations = 0; + _num_invisible_param_annotations = 0; _param_annotations = NULL; + _invisible_param_annotations = NULL; _default_value = NULL; pending_breakpoints = 0; Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/Class_File_Loader.cpp URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/Class_File_Loader.cpp?view=diff&rev=490202&r1=490201&r2=490202 ============================================================================== --- harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/Class_File_Loader.cpp (original) +++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/Class_File_Loader.cpp Mon Dec 25 16:07:25 2006 @@ -48,15 +48,13 @@ // // TODO list: -// -// (1) verify correctness of Method access_flags for different class file versions -// (2) verify correctness of Field access_flags for different class file versions -// (3) verify Class access_flags for different class file versions -// (4) check that Signature of attribute LocalVariableTypeTable of Code attribute is valid -// (5) implement functionality of RuntimeInvisibleAnnotations -// and RuntimeInvisibleParameterAnnotations, not just skip them -// (6) check Signature attribute, not only parse it -// +// (1) Make macro valid_cpi function static bool, add ClassFormatError reporting to valid_cpi, +// replace functions is_valid_index and is_ by valid_cpi. +// (2) Funtion parse_annotation_value doesn't report ClassFormatError in case +// const_inx is invalid. +// (3) Implement field and method name check for 45 and lower versions of class file. + +// #define REPORT_FAILED_CLASS_FORMAT(klass, msg) \ { \ @@ -69,8 +67,6 @@ (clss->get_constant_pool().is_valid_index(idx) \ && clss->get_constant_pool().get_tag(idx) == type) - - static String* cp_check_utf8(ConstantPool& cp, unsigned utf8_index) { if(!cp.is_valid_index(utf8_index) || !cp.is_utf8(utf8_index)) { @@ -542,13 +538,30 @@ return read_len; } +static uint32 parse_parameter_annotations(AnnotationTable *** table, + uint8 num_annotations, + ByteReader& cfs, Class* clss) +{ + *table = (AnnotationTable**)clss->get_class_loader()->Alloc( + num_annotations * sizeof (AnnotationTable*)); + //FIXME: verav should throw OOM + uint32 len = 0; + for (unsigned i = 0; i < num_annotations; i++) + { + uint32 next_len = parse_annotation_table(*table + i, cfs, clss); + if(next_len == 0) + return 0; + len += next_len; + } + return len; +} + void* Class_Member::Alloc(size_t size) { ClassLoader* cl = get_class()->get_class_loader(); assert(cl); return cl->Alloc(size); } - bool Class_Member::parse(Class* clss, ByteReader &cfs) { if (!cfs.parse_u2_be(&_access_flags)) { @@ -596,7 +609,7 @@ // further constrained so that, with the exception of the special method names (§3.9) // and , they must not contain the characters ’<’ or ’>’. static inline bool -check_field_name(const char *name, unsigned len) +check_field_name(const char *name, unsigned len, bool old_version) { for (unsigned i = 0; i < len; i++) { switch(name[i]){ @@ -611,7 +624,7 @@ } static inline bool -check_method_name(const char *name, unsigned len) +check_method_name(const char *name, unsigned len, bool version) { for (unsigned i = 0; i < len; i++) { switch(name[i]){ @@ -666,7 +679,7 @@ return false; } if(*iterator == '/') { - if(!check_field_name(descriptor, id_len)) + if(!check_field_name(descriptor, id_len, false)) return false; id_len = 0; descriptor = iterator + 1; @@ -674,7 +687,7 @@ id_len++; } } - if(!check_field_name(descriptor, id_len)) + if(!check_field_name(descriptor, id_len, false)) return false; *next = iterator + 1; return true; @@ -696,16 +709,21 @@ // DIE( "unreachable code!" ); // exclude remark #111: statement is unreachable } -bool Field::parse(Class *clss, ByteReader &cfs) +//checks of field and method name depend on class version +static const uint16 JAVA5_CLASS_FILE_VERSION = 49; + +bool Field::parse(Global_Env& env, Class *clss, ByteReader &cfs ) { if(!Class_Member::parse(clss, cfs)) return false; - if(!check_field_name(_name->bytes, _name->len)) { + if(env.verify_all + && !check_field_name(_name->bytes, _name->len, + clss->get_version() < JAVA5_CLASS_FILE_VERSION)) + { REPORT_FAILED_CLASS_FORMAT(clss, "illegal field name : " << _name->bytes); return false; } - // check field descriptor //See specification 4.4.2 about field descriptors. const char* next; @@ -716,24 +734,32 @@ // check fields access flags //See specification 4.6 about access flags - if( clss->is_interface() ) { + if(clss->is_interface()) { // check interface fields access flags if(!(is_public() && is_static() && is_final())){ REPORT_FAILED_CLASS_FORMAT(clss, "interface field " << get_name()->bytes - << " does not have one of ACC_PUBLIC, ACC_STATIC, or ACC_FINAL access flags set"); + << " has invalid combination of access flags: " + << "0x" << std::hex << _access_flags); return false; } if(_access_flags & ~(ACC_FINAL | ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC)){ REPORT_FAILED_CLASS_FORMAT(clss, "interface field " << get_name()->bytes - << " has illegal access flags set : " << _access_flags); //FIXME to literal form + << " has invalid combination of access flags: " + << "0x"<< std::hex << _access_flags); return false; } + if(clss->get_version() < JAVA5_CLASS_FILE_VERSION) { + //for class file version lower than 49 these two flags should be set to zero + //See specification 4.5 Fields, for 1.4 Java. + _access_flags &= ~(ACC_SYNTHETIC | ACC_ENUM); + } } else if((is_public() && is_protected() || is_protected() && is_private() || is_public() && is_private()) || (is_final() && is_volatile())) { REPORT_FAILED_CLASS_FORMAT(clss, " field " << get_name()->bytes - << " has invalid combination of access flags : " << _access_flags); //FIXME to literal form + << " has invalid combination of access flags: " + << "0x" << std::hex << _access_flags); return false; } @@ -875,6 +901,11 @@ const_value.string = cp.get_string(_const_value_index); break; } + case CONSTANT_UnusedEntry: + { + //do nothing here + break; + } default: { REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, @@ -935,6 +966,8 @@ } uint32 read_len = parse_annotation_table(&_annotations, cfs, clss); + if(read_len == 0) + return false; if (attr_len != read_len) { REPORT_FAILED_CLASS_FORMAT(clss, "error parsing Annotations attribute" @@ -947,15 +980,30 @@ case ATTR_RuntimeInvisibleAnnotations: { + // Each field_info structure may contain at most one RuntimeInvisibleAnnotations attribute. if(++numRuntimeInvisibleAnnotations > 1) { REPORT_FAILED_CLASS_FORMAT(clss, "more than one RuntimeVisibleAnnotations attribute"); return false; } - if(!cfs.skip(attr_len)) { - REPORT_FAILED_CLASS_FORMAT(clss, - "failed to skip RuntimeInvisibleAnnotations attribute"); - return false; + if(env.retain_invisible_annotations) { + uint32 read_len = + parse_annotation_table(&_invisible_annotations, cfs, clss); + if(read_len == 0) + return false; + if(attr_len != read_len) { + REPORT_FAILED_CLASS_FORMAT(clss, + "error parsing RuntimeInvisibleAnnotations attribute" + << "; declared length " << attr_len + << " does not match actual " << read_len); + return false; + } + } else { + if(!cfs.skip(attr_len)) { + REPORT_FAILED_CLASS_FORMAT(clss, + "failed to skip RuntimeInvisibleAnnotations attribute"); + return false; + } } } break; @@ -1217,7 +1265,8 @@ return false; } - if(!check_field_name(name->bytes, name->len)) + if(!check_field_name(name->bytes, name->len, + _class->get_version() < JAVA5_CLASS_FILE_VERSION)) { REPORT_FAILED_METHOD("name of local variable: " << name->bytes << " in " << attr_name << " attribute is not stored as unqualified name"); @@ -1247,10 +1296,18 @@ "in " << attr_name << " attribute"); return false; } + //See specification about index value 4.8.11 and 4.8.12 + if((descriptor->bytes[0] == 'D' || descriptor->bytes[0] == 'J') + && index >= _max_locals - 1) + { + REPORT_FAILED_METHOD("invalid local index " + << index << " in " << attr_name << " attribute"); + return false; + } if (index >= _max_locals) { REPORT_FAILED_METHOD("invalid local index " - "in " << attr_name << " attribute"); + << index << " in " << attr_name << " attribute"); return false; } @@ -1274,8 +1331,8 @@ &&table->table[j].length == table->table[i].length &&table->table[j].index == table->table[i].index) { - REPORT_FAILED_METHOD("Duplicate attribute "<< attr_name - <<" for local variable "); + REPORT_FAILED_METHOD("Duplicate local variable "<< table->table[j].name + << " in attribute " << attr_name); return false; } } @@ -1328,9 +1385,9 @@ || (_byte_code_length >= (1<<16))) { REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError", - _class->get_name()->bytes << ": bytecode length for method " - << _name->bytes << _descriptor->bytes - << " has zero or exceeding length"); + _class->get_name()->bytes << ": invalid bytecode length " + << _byte_code_length << " for method " + << _name->bytes << _descriptor->bytes); return false; } @@ -1648,10 +1705,11 @@ { if(!Class_Member::parse(clss, cfs)) return false; - - if(!(_name == env.Init_String || _name == env.Clinit_String)) + //check name only if flag verify_all is set from command line + if(env.verify_all && !(_name == env.Init_String || _name == env.Clinit_String)) { - if(!check_method_name(_name->bytes, _name->len)) + if(!check_method_name(_name->bytes, _name->len, + clss->get_version() < JAVA5_CLASS_FILE_VERSION)) { REPORT_FAILED_CLASS_FORMAT(clss, "illegal method name : " << _name->bytes); return false; @@ -1673,8 +1731,8 @@ if(_arguments_slot_num > 255) { REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError", _class->get_name()->bytes << - ": method has more than 255 arguments " - << _name->bytes ); + ": method " << _name->bytes << _descriptor->bytes + << " has more than 255 arguments " ); return false; } // checked method descriptor @@ -1692,61 +1750,68 @@ // check method access flags if(!is_clinit()) { - if(is_private() && is_protected() || is_private() && is_public() || is_protected() && is_public()) - { - bool bout = false; - //See specification 4.7 Methods about access_flags - REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError", - _class->get_name()->bytes << ": invalid combination of access flags (" - << ((bout = is_public())?"ACC_PUBLIC":"") - << (bout?"|":"") - << ((bout |= is_protected())?"ACC_PROTECTED":"") - << (bout?"|":"") - << (is_private()?"ACC_PRIVATE":"") - << ") for method " - << _name->bytes << _descriptor->bytes); - return false; - } - if(is_abstract() - && (is_final() || is_native() || is_private() || is_static() || is_strict() || is_synchronized())) - { - bool bout = false; - REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError", - _class->get_name()->bytes << ": invalid combination of access flags (ACC_ABSTRACT|" - << ((bout = is_final())?"ACC_FINAL":"") - << (bout?"|":"") - << ((bout |= is_native())?"ACC_NATIVE":"") - << (bout?"|":"") - << ((bout |= is_private())?"ACC_PRIVATE":"") - << (bout?"|":"") - << ((bout |= is_static())?"ACC_STATIC":"") - << (bout?"|":"") - << ((bout |= is_strict())?"ACC_STRICT":"") - << (bout?"|":"") - << ((bout |= is_synchronized())?"ACC_SYNCHRONIZED":"") - << ") for method " - << _name->bytes << _descriptor->bytes); - return false; - } if(_class->is_interface()) { if(!(is_abstract() && is_public())){ REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError", _class->get_name()->bytes << "." << _name->bytes << _descriptor->bytes - << ": interface method must have access flags " + << ": interface method must have both access flags " "ACC_ABSTRACT and ACC_PUBLIC set" ); return false; } - if(_access_flags & ~(ACC_ABSTRACT | ACC_PUBLIC | ACC_VARARGS | ACC_BRIDGE | ACC_SYNTHETIC)){ + if(_access_flags & ~(ACC_ABSTRACT | ACC_PUBLIC | ACC_VARARGS + | ACC_BRIDGE | ACC_SYNTHETIC)){ REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError", - _class->get_name()->bytes << "." << _name->bytes << _descriptor->bytes - << ": interface method cannot have access flags other then " - "ACC_ABSTRACT, ACC_PUBLIC, ACC_VARARG, ACC_BRIDGES or ACC_SYNTHETIC set"); + _class->get_name()->bytes << " Interface method " + << _name->bytes << _descriptor->bytes + << " has invalid combination of access flags " + << "0x" << std::hex << _access_flags); return false; } - } - + //for class file version lower than 49 these three flags should be set to zero + //See specification 4.6 Methods, for 1.4 Java. + if(_class->get_version() < JAVA5_CLASS_FILE_VERSION){ + _access_flags &= ~(ACC_BRIDGE | ACC_VARARGS | ACC_SYNTHETIC); + } + } else { + if(is_private() && is_protected() + || is_private() && is_public() + || is_protected() && is_public()) + { + //See specification 4.7 Methods about access_flags + REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError", + _class->get_name()->bytes << "Method " + << _name->bytes << _descriptor->bytes + << " has invalid combination of access flags " + << "0x" << std::hex << _access_flags); + return false; + } + if(is_abstract() + && (is_final() || is_native() || is_private() + || is_static() || is_strict() || is_synchronized())) + { + bool bout = false; + REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError", + _class->get_name()->bytes << " Method " + << _name->bytes << _descriptor->bytes + << " has invalid combination of access flags " + << "0x" << std::hex << _access_flags); + return false; + } + if(is_init()) { + if(_access_flags & ~(ACC_STRICT | ACC_VARARGS | ACC_SYNTHETIC + | ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED)) + { + REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError", + _class->get_name()->bytes << " Method " + << _name->bytes << _descriptor->bytes + << " has invalid combination of access flags " + << "0x" << std::hex << _access_flags); + return false; + } + } + } } else { // Java VM specification // 4.7 Methods @@ -1761,14 +1826,6 @@ _access_flags |= ACC_STATIC; } - if(is_init() && (is_static() || is_final() || is_synchronized() || is_native() || is_abstract() || is_bridge())) { - REPORT_FAILED_CLASS_CLASS(_class->get_class_loader(), _class, "java/lang/ClassFormatError", - _class->get_name()->bytes << "." << _name->bytes << _descriptor->bytes - << ": constructor cannot have access flags other then " - "ACC_STRICT, ACC_VARARGS, ACC_SYNTHETIC and one of ACC_PUBLIC, ACC_PRIVATE, or ACC_PROTECTED set"); - return false; - } - //check method attributes uint16 attr_count; if(!cfs.parse_u2_be(&attr_count)) { @@ -1823,16 +1880,43 @@ break; case ATTR_RuntimeInvisibleParameterAnnotations: - if(++numRuntimeInvisibleParameterAnnotations > 1) { - REPORT_FAILED_CLASS_FORMAT(clss, - "more than one RuntimeInvisibleParameterAnnotations attribute"); - return false; - } - - if (!cfs.skip(attr_len)) { - REPORT_FAILED_METHOD("error skipping RuntimeInvisibleParameterAnnotations"); - return false; + //RuntimeInvisibleParameterAnnotations attribute is parsed only if + //command line option -Xinvisible is set. See specification 4.8.17. + if(env.retain_invisible_annotations) { + if(++numRuntimeInvisibleParameterAnnotations > 1) { + REPORT_FAILED_CLASS_FORMAT(clss, + "more than one RuntimeInvisibleParameterAnnotations attribute"); + return false; + } + if (!cfs.parse_u1(&_num_invisible_param_annotations)) { + REPORT_FAILED_CLASS_FORMAT(clss, + "cannot parse number of InvisibleParameterAnnotations"); + return false; + } + uint32 read_len = 1; + if (_num_invisible_param_annotations) { + uint32 len = + parse_parameter_annotations(&_invisible_param_annotations, + _num_invisible_param_annotations, cfs, _class); + if(len == 0) + return false; + read_len += len; + } + if (attr_len != read_len) { + REPORT_FAILED_METHOD( + "error parsing InvisibleParameterAnnotations attribute" + << "; declared length " << attr_len + << " does not match actual " << read_len); + return false; + } + } else { + if (!cfs.skip(attr_len)) + { + REPORT_FAILED_METHOD("error skipping RuntimeInvisibleParameterAnnotations"); + return false; + } + } } break; @@ -1852,17 +1936,11 @@ } uint32 read_len = 1; if (_num_param_annotations) { - _param_annotations = (AnnotationTable**)_class->get_class_loader()->Alloc( - _num_param_annotations * sizeof (AnnotationTable*)); - //FIXME: verav should throw OOM - for (unsigned i = 0; i < _num_param_annotations; i++) - { - uint32 next_len = parse_annotation_table(_param_annotations + i, cfs, _class); - if (next_len == 0) { - return false; - } - read_len += next_len; - } + uint32 len = parse_parameter_annotations(&_param_annotations, + _num_param_annotations, cfs, _class); + if(len == 0) + return false; + read_len += len; } if (attr_len != read_len) { REPORT_FAILED_METHOD( @@ -1943,6 +2021,8 @@ } uint32 read_len = parse_annotation_table(&_annotations, cfs, clss); + if(read_len == 0) + return false; if (attr_len != read_len) { REPORT_FAILED_CLASS_FORMAT(clss, "error parsing Annotations attribute" @@ -1961,11 +2041,26 @@ "more than one RuntimeInvisibleAnnotations attribute"); return false; } - - if(!cfs.skip(attr_len)) { - REPORT_FAILED_CLASS_FORMAT(clss, - "failed to skip RuntimeInvisibleAnnotations attribute"); - return false; + //RuntimeInvisibleAnnotations attribute is parsed only if + //command line option -Xinvisible is set. See specification 4.8.15. + if(env.retain_invisible_annotations) { + uint32 read_len = + parse_annotation_table(&_invisible_annotations, cfs, clss); + if(read_len == 0) + return false; + if (attr_len != read_len) { + REPORT_FAILED_CLASS_FORMAT(clss, + "error parsing RuntimeInvisibleAnnotations attribute" + << "; declared length " << attr_len + << " does not match actual " << read_len); + return false; + } + }else { + if(!cfs.skip(attr_len)) { + REPORT_FAILED_CLASS_FORMAT(clss, + "failed to skip RuntimeInvisibleAnnotations attribute"); + return false; + } } } break; @@ -2043,7 +2138,7 @@ unsigned short last_nonstatic_field = (unsigned short)num_fields_in_class_file; for(i=0; i < num_fields_in_class_file; i++) { Field fd; - if(!fd.parse(this, cfs)) + if(!fd.parse(*env, this, cfs)) return false; if(fd.is_static()) { m_fields[m_num_static_fields] = fd; @@ -2170,14 +2265,14 @@ id_len++; }else { - if(!check_field_name(name, id_len)) + if(!check_field_name(name, id_len, false)) return false; id_len = 0; name = iterator; name++; } } - return check_field_name(name, id_len); + return check_field_name(name, id_len, false); } return false; //unreacheable code } @@ -2187,19 +2282,21 @@ { // buffer ends before len if(!cfs.have(len)) - return false; + return NULL; // get utf8 bytes and move buffer pointer - const char* utf8data = (const char*)cfs.get_and_skip(len); + uint8* utf8data = (uint8*)cfs.get_and_skip(len); // FIXME: decode 6-byte Java 1.5 encoding // check utf8 correctness - if(memchr(utf8data, 0, len) != NULL) - return false; + int i; + for(i = 0; i < len && utf8data[i] != 0x00 && utf8data[i] < 0xf0; i++); + if(i < len) + return NULL; // then lookup on utf8 bytes and return string - return string_pool.lookup(utf8data, len); + return string_pool.lookup((const char*)utf8data, len); } @@ -2208,7 +2305,7 @@ { uint16 len; if(!cfs.parse_u2_be(&len)) - return false; + return NULL; return class_file_parse_utf8data(string_pool, cfs, len); } @@ -2304,7 +2401,11 @@ return false; } // skip next constant pool entry as it is used by next 4 bytes of Long/Double - cp_tags[i+1] = cp_tags[i]; + if(i + 1 < m_size) { + cp_tags[i+1] = CONSTANT_UnusedEntry; + m_entries[i+1].CONSTANT_8byte.high_bytes = m_entries[i].CONSTANT_8byte.high_bytes; + m_entries[i+1].CONSTANT_8byte.low_bytes = m_entries[i].CONSTANT_8byte.low_bytes; + } i++; break; @@ -2337,7 +2438,7 @@ break; default: REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError", - clss->get_name()->bytes << ": unknown constant pool tag " << cp_tags[i]); + clss->get_name()->bytes << ": unknown constant pool tag " << "0x" << std::hex << (int)cp_tags[i]); return false; } } @@ -2347,8 +2448,6 @@ bool ConstantPool::check(Global_Env* env, Class* clss) { - - for(unsigned i = 1; i < m_size; i++) { switch(unsigned char tag = get_tag(i)) { @@ -2409,7 +2508,8 @@ //check method name if(name != env->Init_String) { - if(!check_method_name(name->bytes,name->len)) + if(!check_method_name(name->bytes,name->len, + clss->get_version() < JAVA5_CLASS_FILE_VERSION)) { REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError", clss->get_name()->bytes << ": illegal method name for CONSTANT_Methodref entry: " << name->bytes); @@ -2440,7 +2540,8 @@ if(tag == CONSTANT_Fieldref) { //check field name - if(!check_field_name(name->bytes, name->len)) + if(!check_field_name(name->bytes, name->len, + clss->get_version() < JAVA5_CLASS_FILE_VERSION)) { REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError", clss->get_name()->bytes << ": illegal filed name for CONSTANT_Filedref entry: " << name->bytes); @@ -2458,7 +2559,8 @@ { //check method name, name can't be or //See specification 4.5.2 about name_and_type_index last sentence. - if(!check_method_name(name->bytes, name->len)) + if(!check_method_name(name->bytes, name->len, + clss->get_version() < JAVA5_CLASS_FILE_VERSION)) { REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError", clss->get_name()->bytes << ": illegal filed name for CONSTANT_InterfaceMethod entry: " << name->bytes); @@ -2495,11 +2597,12 @@ case CONSTANT_Double: //check Long and Double indexes, n+1 index should be valid too. //See specification 4.5.5 - if( i + 1 > m_size){ + if(i + 1 == m_size){ REPORT_FAILED_CLASS_CLASS(clss->get_class_loader(), clss, "java/lang/ClassFormatError", clss->get_name()->bytes << ": illegal indexes for Long or Double " << i << " and " << i + 1); return false; } + i++; break; case CONSTANT_NameAndType: { @@ -2647,7 +2750,7 @@ return false; } - if(m_version == 49 && minor_version > 0) + if(m_version == JAVA5_CLASS_FILE_VERSION && minor_version > 0) { REPORT_FAILED_CLASS_CLASS(m_class_loader, this, "java/lang/UnsupportedClassVersionError", "unsupported class file version " << m_version << "." << minor_version); @@ -2693,7 +2796,7 @@ REPORT_FAILED_CLASS_FORMAT(this, "interface cannot be final"); return false; } - //not only ACC_FINAL flag is prohibited if is_interface, also ACC_SUPER, ACC_SYNTHETIC, ACC_ENUM. + //not only ACC_FINAL flag is prohibited if is_interface, also ACC_SYNTHETIC and ACC_ENUM. if(is_interface() && (is_synthetic() || is_enum())) { REPORT_FAILED_CLASS_FORMAT(this, @@ -2716,7 +2819,12 @@ REPORT_FAILED_CLASS_FORMAT(this, "not interface can't be annotation"); return false; } - + //for class file version lower than 49 these three flags should be set to zero + //See specification 4.5 Fields, for 1.4 Java. + if(m_version < JAVA5_CLASS_FILE_VERSION) { + m_access_flags &= ~(ACC_SYNTHETIC | ACC_ENUM | ACC_ANNOTATION); + } + /* * parse this_class & super_class & verify their constant pool entries */ @@ -3098,9 +3206,11 @@ return false; } uint32 read_len = parse_annotation_table(&m_annotations, cfs, this); + if(attr_len == 0) + return false; if (attr_len != read_len) { REPORT_FAILED_CLASS_FORMAT(this, - "error parsing Annotations attribute" + "error parsing RuntimeVisibleAnnotations attribute" << "; declared length " << attr_len << " does not match actual " << read_len); return false; @@ -3110,16 +3220,29 @@ case ATTR_RuntimeInvisibleAnnotations: { - //ClassFile may contain at most one RuntimeInvisibleAnnotations attribute. - if(++numRuntimeInvisibleAnnotations > 1) { - REPORT_FAILED_CLASS_FORMAT(this, - "more than one RuntimeInvisibleAnnotations attribute"); - return false; - } - if(!cfs.skip(attr_len)) { - REPORT_FAILED_CLASS_FORMAT(this, - "failed to skip RuntimeInvisibleAnnotations attribute"); - return false; + if(env->retain_invisible_annotations) { + //ClassFile may contain at most one RuntimeInvisibleAnnotations attribute. + if(++numRuntimeInvisibleAnnotations > 1) { + REPORT_FAILED_CLASS_FORMAT(this, + "more than one RuntimeInvisibleAnnotations attribute"); + return false; + } + uint32 read_len = parse_annotation_table(&m_invisible_annotations, cfs, this); + if(read_len == 0) + return false; + if (attr_len != read_len) { + REPORT_FAILED_CLASS_FORMAT(this, + "error parsing RuntimeInvisibleAnnotations attribute" + << "; declared length " << attr_len + << " does not match actual " << read_len); + return false; + } + }else { + if(!cfs.skip(attr_len)) { + REPORT_FAILED_CLASS_FORMAT(this, + "failed to skip RuntimeInvisibleAnnotations attribute"); + return false; + } } } break; Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/Environment.cpp URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/Environment.cpp?view=diff&rev=490202&r1=490201&r2=490202 ============================================================================== --- harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/Environment.cpp (original) +++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/Environment.cpp Mon Dec 25 16:07:25 2006 @@ -136,6 +136,7 @@ verify_all = false; pin_interned_strings = false; + retain_invisible_annotations = false; // initialize critical sections p_jit_a_method_lock = new Lock_Manager(); Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/Resolve.cpp URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/Resolve.cpp?view=diff&rev=490202&r1=490201&r2=490202 ============================================================================== --- harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/Resolve.cpp (original) +++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/class_support/Resolve.cpp Mon Dec 25 16:07:25 2006 @@ -1048,6 +1048,7 @@ return true; case CONSTANT_Double: // fall through case CONSTANT_Long: + case CONSTANT_UnusedEntry: return true; } return false; Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/src/init/parse_arguments.cpp URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/init/parse_arguments.cpp?view=diff&rev=490202&r1=490201&r2=490202 ============================================================================== --- harmony/enhanced/drlvm/trunk/vm/vmcore/src/init/parse_arguments.cpp (original) +++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/init/parse_arguments.cpp Mon Dec 25 16:07:25 2006 @@ -177,6 +177,8 @@ " Log verbose output to a file\n" " -Xverify\n" " Do full bytecode verification\n" + " -Xinvisible\n" + " Retain invisible annotations at runtime\n" " -Xfileline\n" " Add source information to logging messages\n" " -Xthread\n" @@ -434,6 +436,9 @@ } else if (strcmp(option, "-Xdebug") == 0) { // Do nothing, this option is only for compatibility with old JREs + } + else if (strcmp(option, "-Xinvisible") == 0) { + p_env->retain_invisible_annotations = true; } else if (strcmp(option, "-Xverify") == 0) { p_env->verify_all = true; Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMGenericsAndAnnotations.cpp URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMGenericsAndAnnotations.cpp?view=diff&rev=490202&r1=490201&r2=490202 ============================================================================== --- harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMGenericsAndAnnotations.cpp (original) +++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/kernel_classes/native/org_apache_harmony_vm_VMGenericsAndAnnotations.cpp Mon Dec 25 16:07:25 2006 @@ -62,7 +62,9 @@ { Class_Member* member = (Class_Member*) ((POINTER_SIZE_INT) jmember); TRACE("Requested annotations for member " << member); - return get_annotations(jenv, member->get_declared_annotations(), member->get_class()); + return get_annotations(jenv, member->get_declared_annotations(), + member->get_declared_invisible_annotations(), + member->get_class()); } JNIEXPORT jobjectArray JNICALL Java_org_apache_harmony_vm_VMGenericsAndAnnotations_getDeclaredAnnotations__Ljava_lang_Class_2 @@ -70,7 +72,8 @@ { Class* clazz = jclass_to_struct_Class(jclazz); TRACE("Requested annotations for class " << clazz); - return get_annotations(jenv, clazz->get_annotations(), clazz); + return get_annotations(jenv, clazz->get_annotations(), + clazz->get_invisible_annotations(), clazz); } JNIEXPORT jobjectArray JNICALL Java_org_apache_harmony_vm_VMGenericsAndAnnotations_getParameterAnnotations @@ -83,7 +86,8 @@ static Class* array_class = genv->LoadCoreClass( "[Ljava/lang/annotation/Annotation;"); - unsigned num = method->get_num_param_annotations(); + unsigned param_num = method->get_num_param_annotations(); + unsigned num = param_num + method->get_num_invisible_param_annotations(); TRACE("Requested parameters annotations for method " << method << "; num=" << num); @@ -113,8 +117,11 @@ return NULL; } - for (unsigned i = 0; i < num; ++i) { - jobject element = get_annotations(jenv, method->get_param_annotations(i), declaring_class); + unsigned i; + for (i = 0; i < param_num; ++i) { + jobject element = get_annotations(jenv, + method->get_param_annotations(i), + NULL, declaring_class); if (!element) { assert(exn_raised()); return NULL; @@ -123,7 +130,19 @@ assert(!exn_raised()); } } - + for (i = param_num; i < num; ++i) { + jobject element = get_annotations(jenv, NULL, + method->get_invisible_param_annotations(i - param_num), + declaring_class); + if (!element) { + assert(exn_raised()); + return NULL; + } else { + SetObjectArrayElement(jenv, array, i, element); + assert(!exn_raised()); + } + } + return array; } Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/src/reflection/annotations.cpp URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/reflection/annotations.cpp?view=diff&rev=490202&r1=490201&r2=490202 ============================================================================== --- harmony/enhanced/drlvm/trunk/vm/vmcore/src/reflection/annotations.cpp (original) +++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/reflection/annotations.cpp Mon Dec 25 16:07:25 2006 @@ -36,10 +36,15 @@ #include "primitives_support.h" #include "vm_log.h" -jobjectArray get_annotations(JNIEnv* jenv, AnnotationTable* table, Class* clss) +jobjectArray get_annotations(JNIEnv* jenv, AnnotationTable* table, AnnotationTable* inv_table, Class* clss) { - unsigned num = table ? table->length : 0; - TRACE("annotations table size = " << num); + unsigned table_num = table ? table->length : 0; + TRACE("annotations table size = " << table_num); + + unsigned inv_table_num = inv_table ? inv_table->length : 0; + TRACE("invisible annotations table size = " << inv_table_num); + + unsigned num = table_num + inv_table_num; static Class* antn_class = jni_get_vm_env(jenv)->LoadCoreClass( "java/lang/annotation/Annotation"); @@ -52,7 +57,8 @@ return NULL; } - for (unsigned i = 0; i < num; ++i) { + unsigned i; + for (i = 0; i < table_num; ++i) { jobject element = resolve_annotation(jenv, table->table[i], clss); if (!element) { assert(exn_raised()); @@ -62,7 +68,16 @@ assert(!exn_raised()); } } - + for (i = table_num; i < num; ++i) { + jobject element = resolve_annotation(jenv, inv_table->table[i - table_num], clss); + if (!element) { + assert(exn_raised()); + return NULL; + } else { + SetObjectArrayElement(jenv, array, i, element); + assert(!exn_raised()); + } + } return array; }