--- old/src/share/vm/classfile/classFileParser.cpp 2017-02-27 08:38:42.675119025 -0500 +++ new/src/share/vm/classfile/classFileParser.cpp 2017-02-27 08:38:42.415844255 -0500 @@ -105,13 +105,22 @@ #define JAVA_9_VERSION 53 -void ClassFileParser::parse_constant_pool_entries(const ClassFileStream* const stream, - ConstantPool* cp, - const int length, - TRAPS) { +int ClassFileParser::parse_constant_pool_entries(const ClassFileStream* const stream, + ConstantPool* cp, + const int length, + TRAPS) { assert(stream != NULL, "invariant"); assert(cp != NULL, "invariant"); + // Used to keep track of whether a constant pool item 19 or 20 is found. These + // correspond to CONSTANT_Module and CONSTANT_Package tags and are not allowed + // in regular class files. For class file version >= 53, a CFE cannot be thrown + // immediately when these are seen because a NCDFE must be thrown if the class's + // access_flags have ACC_MODULE set. But, the access_flags haven't been looked + // at yet. So, the bad constant pool item is cached here and returned as the + // function result. Returning zero means no constant pool item 19 or 20 was found. + int bad_tag = 0; + // Use a local copy of ClassFileStream. It helps the C++ compiler to optimize // this function (_current can be allocated in a register, with scalar // replacement of aggregates). The _current pointer is copied back to @@ -138,34 +147,34 @@ const u1 tag = cfs->get_u1_fast(); switch (tag) { case JVM_CONSTANT_Class : { - cfs->guarantee_more(3, CHECK); // name_index, tag/access_flags + cfs->guarantee_more(3, CHECK_0); // name_index, tag/access_flags const u2 name_index = cfs->get_u2_fast(); cp->klass_index_at_put(index, name_index); break; } case JVM_CONSTANT_Fieldref: { - cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags + cfs->guarantee_more(5, CHECK_0); // class_index, name_and_type_index, tag/access_flags const u2 class_index = cfs->get_u2_fast(); const u2 name_and_type_index = cfs->get_u2_fast(); cp->field_at_put(index, class_index, name_and_type_index); break; } case JVM_CONSTANT_Methodref: { - cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags + cfs->guarantee_more(5, CHECK_0); // class_index, name_and_type_index, tag/access_flags const u2 class_index = cfs->get_u2_fast(); const u2 name_and_type_index = cfs->get_u2_fast(); cp->method_at_put(index, class_index, name_and_type_index); break; } case JVM_CONSTANT_InterfaceMethodref: { - cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags + cfs->guarantee_more(5, CHECK_0); // class_index, name_and_type_index, tag/access_flags const u2 class_index = cfs->get_u2_fast(); const u2 name_and_type_index = cfs->get_u2_fast(); cp->interface_method_at_put(index, class_index, name_and_type_index); break; } case JVM_CONSTANT_String : { - cfs->guarantee_more(3, CHECK); // string_index, tag/access_flags + cfs->guarantee_more(3, CHECK_0); // string_index, tag/access_flags const u2 string_index = cfs->get_u2_fast(); cp->string_index_at_put(index, string_index); break; @@ -175,16 +184,16 @@ if (_major_version < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) { classfile_parse_error( "Class file version does not support constant tag %u in class file %s", - tag, CHECK); + tag, CHECK_0); } if (tag == JVM_CONSTANT_MethodHandle) { - cfs->guarantee_more(4, CHECK); // ref_kind, method_index, tag/access_flags + cfs->guarantee_more(4, CHECK_0); // ref_kind, method_index, tag/access_flags const u1 ref_kind = cfs->get_u1_fast(); const u2 method_index = cfs->get_u2_fast(); cp->method_handle_index_at_put(index, ref_kind, method_index); } else if (tag == JVM_CONSTANT_MethodType) { - cfs->guarantee_more(3, CHECK); // signature_index, tag/access_flags + cfs->guarantee_more(3, CHECK_0); // signature_index, tag/access_flags const u2 signature_index = cfs->get_u2_fast(); cp->method_type_index_at_put(index, signature_index); } @@ -197,9 +206,9 @@ if (_major_version < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) { classfile_parse_error( "Class file version does not support constant tag %u in class file %s", - tag, CHECK); + tag, CHECK_0); } - cfs->guarantee_more(5, CHECK); // bsm_index, nt, tag/access_flags + cfs->guarantee_more(5, CHECK_0); // bsm_index, nt, tag/access_flags const u2 bootstrap_specifier_index = cfs->get_u2_fast(); const u2 name_and_type_index = cfs->get_u2_fast(); if (_max_bootstrap_specifier_index < (int) bootstrap_specifier_index) { @@ -209,13 +218,13 @@ break; } case JVM_CONSTANT_Integer: { - cfs->guarantee_more(5, CHECK); // bytes, tag/access_flags + cfs->guarantee_more(5, CHECK_0); // bytes, tag/access_flags const u4 bytes = cfs->get_u4_fast(); cp->int_at_put(index, (jint)bytes); break; } case JVM_CONSTANT_Float: { - cfs->guarantee_more(5, CHECK); // bytes, tag/access_flags + cfs->guarantee_more(5, CHECK_0); // bytes, tag/access_flags const u4 bytes = cfs->get_u4_fast(); cp->float_at_put(index, *(jfloat*)&bytes); break; @@ -225,8 +234,8 @@ guarantee_property(index + 1 < length, "Invalid constant pool entry %u in class file %s", index, - CHECK); - cfs->guarantee_more(9, CHECK); // bytes, tag/access_flags + CHECK_0); + cfs->guarantee_more(9, CHECK_0); // bytes, tag/access_flags const u8 bytes = cfs->get_u8_fast(); cp->long_at_put(index, bytes); index++; // Skip entry following eigth-byte constant, see JVM book p. 98 @@ -237,32 +246,32 @@ guarantee_property(index+1 < length, "Invalid constant pool entry %u in class file %s", index, - CHECK); - cfs->guarantee_more(9, CHECK); // bytes, tag/access_flags + CHECK_0); + cfs->guarantee_more(9, CHECK_0); // bytes, tag/access_flags const u8 bytes = cfs->get_u8_fast(); cp->double_at_put(index, *(jdouble*)&bytes); index++; // Skip entry following eigth-byte constant, see JVM book p. 98 break; } case JVM_CONSTANT_NameAndType: { - cfs->guarantee_more(5, CHECK); // name_index, signature_index, tag/access_flags + cfs->guarantee_more(5, CHECK_0); // name_index, signature_index, tag/access_flags const u2 name_index = cfs->get_u2_fast(); const u2 signature_index = cfs->get_u2_fast(); cp->name_and_type_at_put(index, name_index, signature_index); break; } case JVM_CONSTANT_Utf8 : { - cfs->guarantee_more(2, CHECK); // utf8_length + cfs->guarantee_more(2, CHECK_0); // utf8_length u2 utf8_length = cfs->get_u2_fast(); const u1* utf8_buffer = cfs->get_u1_buffer(); assert(utf8_buffer != NULL, "null utf8 buffer"); // Got utf8 string, guarantee utf8_length+1 bytes, set stream position forward. - cfs->guarantee_more(utf8_length+1, CHECK); // utf8 string, tag/access_flags + cfs->guarantee_more(utf8_length+1, CHECK_0); // utf8 string, tag/access_flags cfs->skip_u1_fast(utf8_length); // Before storing the symbol, make sure it's legal if (_need_verify) { - verify_legal_utf8(utf8_buffer, utf8_length, CHECK); + verify_legal_utf8(utf8_buffer, utf8_length, CHECK_0); } if (has_cp_patch_at(index)) { @@ -270,7 +279,7 @@ guarantee_property(java_lang_String::is_instance(patch()), "Illegal utf8 patch at %d in class file %s", index, - CHECK); + CHECK_0); const char* const str = java_lang_String::as_utf8_string(patch()); // (could use java_lang_String::as_symbol instead, but might as well batch them) utf8_buffer = (const u1*) str; @@ -294,7 +303,7 @@ lengths, indices, hashValues, - CHECK); + CHECK_0); names_count = 0; } } else { @@ -302,10 +311,22 @@ } break; } + case 19: + case 20: { + // Record that an error occured in these two cases but keep parsing so + // that ACC_Module can be checked for in the access_flags. Need to + // throw NoClassDefFoundError in that case. + if (_major_version >= JAVA_9_VERSION) { + cfs->guarantee_more(3, CHECK_0); + cfs->get_u2_fast(); + if (bad_tag == 0) bad_tag = tag; + break; + } + } default: { classfile_parse_error("Unknown constant tag %u in class file %s", tag, - CHECK); + CHECK_0); break; } } // end of switch(tag) @@ -320,13 +341,14 @@ lengths, indices, hashValues, - CHECK); + CHECK_0); } // Copy _current pointer of local copy back to stream. assert(stream->current() == old_current, "non-exclusive use of stream"); stream->set_current(cfs1.current()); + return bad_tag; } static inline bool valid_cp_range(int index, int length) { @@ -358,15 +380,24 @@ PRAGMA_DIAG_POP #endif -void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, - ConstantPool* const cp, - const int length, - TRAPS) { +int ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, + ConstantPool* const cp, + const int length, + TRAPS) { assert(cp != NULL, "invariant"); assert(stream != NULL, "invariant"); // parsing constant pool entries - parse_constant_pool_entries(stream, cp, length, CHECK); + int result = parse_constant_pool_entries(stream, cp, length, CHECK_0); + if (result != 0) { + // Either a CONSTANT_Module or CONSTANT_Package entry was found in the constant + // pool. Return it so the caller can decide whether to throw NCDFE if it finds + // ACC_MODULE in the class's access_flags or throw CFE for the bad constant + // pool entry. + assert((result == 19 || result == 20) && _major_version >= JAVA_9_VERSION, + "Unexpected result from parse_constant_pool_entries()"); + return result; + } int index = 1; // declared outside of loops for portability @@ -389,11 +420,11 @@ const int name_and_type_ref_index = cp->name_and_type_ref_index_at(index); check_property(valid_klass_reference_at(klass_ref_index), "Invalid constant pool index %u in class file %s", - klass_ref_index, CHECK); + klass_ref_index, CHECK_0); check_property(valid_cp_range(name_and_type_ref_index, length) && cp->tag_at(name_and_type_ref_index).is_name_and_type(), "Invalid constant pool index %u in class file %s", - name_and_type_ref_index, CHECK); + name_and_type_ref_index, CHECK_0); break; } case JVM_CONSTANT_String: { @@ -410,7 +441,7 @@ check_property( (index < length && cp->tag_at(index).is_invalid()), "Improper constant pool long/double index %u in class file %s", - index, CHECK); + index, CHECK_0); break; } case JVM_CONSTANT_NameAndType: { @@ -419,10 +450,10 @@ const int signature_ref_index = cp->signature_ref_index_at(index); check_property(valid_symbol_at(name_ref_index), "Invalid constant pool index %u in class file %s", - name_ref_index, CHECK); + name_ref_index, CHECK_0); check_property(valid_symbol_at(signature_ref_index), "Invalid constant pool index %u in class file %s", - signature_ref_index, CHECK); + signature_ref_index, CHECK_0); break; } case JVM_CONSTANT_Utf8: @@ -436,7 +467,7 @@ const int class_index = cp->klass_index_at(index); check_property(valid_symbol_at(class_index), "Invalid constant pool index %u in class file %s", - class_index, CHECK); + class_index, CHECK_0); cp->unresolved_klass_at_put(index, cp->symbol_at(class_index)); break; } @@ -444,7 +475,7 @@ const int string_index = cp->string_index_at(index); check_property(valid_symbol_at(string_index), "Invalid constant pool index %u in class file %s", - string_index, CHECK); + string_index, CHECK_0); Symbol* const sym = cp->symbol_at(string_index); cp->unresolved_string_at_put(index, sym); break; @@ -453,7 +484,7 @@ const int ref_index = cp->method_handle_index_at(index); check_property(valid_cp_range(ref_index, length), "Invalid constant pool index %u in class file %s", - ref_index, CHECK); + ref_index, CHECK_0); const constantTag tag = cp->tag_at(ref_index); const int ref_kind = cp->method_handle_ref_kind_at(index); @@ -465,7 +496,7 @@ check_property( tag.is_field(), "Invalid constant pool index %u in class file %s (not a field)", - ref_index, CHECK); + ref_index, CHECK_0); break; } case JVM_REF_invokeVirtual: @@ -473,7 +504,7 @@ check_property( tag.is_method(), "Invalid constant pool index %u in class file %s (not a method)", - ref_index, CHECK); + ref_index, CHECK_0); break; } case JVM_REF_invokeStatic: @@ -482,20 +513,20 @@ tag.is_method() || ((_major_version >= JAVA_8_VERSION) && tag.is_interface_method()), "Invalid constant pool index %u in class file %s (not a method)", - ref_index, CHECK); + ref_index, CHECK_0); break; } case JVM_REF_invokeInterface: { check_property( tag.is_interface_method(), "Invalid constant pool index %u in class file %s (not an interface method)", - ref_index, CHECK); + ref_index, CHECK_0); break; } default: { classfile_parse_error( "Bad method handle kind at constant pool index %u in class file %s", - index, CHECK); + index, CHECK_0); } } // switch(refkind) // Keep the ref_index unchanged. It will be indirected at link-time. @@ -505,7 +536,7 @@ const int ref_index = cp->method_type_index_at(index); check_property(valid_symbol_at(ref_index), "Invalid constant pool index %u in class file %s", - ref_index, CHECK); + ref_index, CHECK_0); break; } case JVM_CONSTANT_InvokeDynamic: { @@ -515,7 +546,7 @@ check_property(valid_cp_range(name_and_type_ref_index, length) && cp->tag_at(name_and_type_ref_index).is_name_and_type(), "Invalid constant pool index %u in class file %s", - name_and_type_ref_index, CHECK); + name_and_type_ref_index, CHECK_0); // bootstrap specifier index must be checked later, // when BootstrapMethods attr is available break; @@ -532,7 +563,7 @@ // need to treat this_class specially... int this_class_index; { - stream->guarantee_more(8, CHECK); // flags, this_class, super_class, infs_len + stream->guarantee_more(8, CHECK_0); // flags, this_class, super_class, infs_len const u1* const mark = stream->current(); stream->skip_u2_fast(1); // skip flags this_class_index = stream->get_u2_fast(); @@ -543,14 +574,14 @@ if (has_cp_patch_at(index)) { guarantee_property(index != this_class_index, "Illegal constant pool patch to self at %d in class file %s", - index, CHECK); - patch_constant_pool(cp, index, cp_patch_at(index), CHECK); + index, CHECK_0); + patch_constant_pool(cp, index, cp_patch_at(index), CHECK_0); } } } if (!_need_verify) { - return; + return 0; } // second verification pass - checks the strings are of the right format. @@ -561,7 +592,7 @@ case JVM_CONSTANT_UnresolvedClass: { const Symbol* const class_name = cp->klass_name_at(index); // check the name, even if _cp_patches will overwrite it - verify_legal_class_name(class_name, CHECK); + verify_legal_class_name(class_name, CHECK_0); break; } case JVM_CONSTANT_NameAndType: { @@ -572,19 +603,19 @@ const Symbol* const sig = cp->symbol_at(sig_index); guarantee_property(sig->utf8_length() != 0, "Illegal zero length constant pool entry at %d in class %s", - sig_index, CHECK); + sig_index, CHECK_0); guarantee_property(name->utf8_length() != 0, "Illegal zero length constant pool entry at %d in class %s", - name_index, CHECK); + name_index, CHECK_0); if (sig->byte_at(0) == JVM_SIGNATURE_FUNC) { // Format check method name and signature - verify_legal_method_name(name, CHECK); - verify_legal_method_signature(name, sig, CHECK); + verify_legal_method_name(name, CHECK_0); + verify_legal_method_signature(name, sig, CHECK_0); } else { // Format check field name and signature - verify_legal_field_name(name, CHECK); - verify_legal_field_signature(name, sig, CHECK); + verify_legal_field_name(name, CHECK_0); + verify_legal_field_signature(name, sig, CHECK_0); } } break; @@ -609,7 +640,7 @@ // Need only to be sure signature is non-zero length and the right type. if (signature->utf8_length() == 0 || signature->byte_at(0) == JVM_SIGNATURE_FUNC) { - throwIllegalSignature("Field", name, signature, CHECK); + throwIllegalSignature("Field", name, signature, CHECK_0); } } } else { @@ -618,7 +649,7 @@ // Need only to be sure signature is non-zero length and the right type. if (signature->utf8_length() == 0 || signature->byte_at(0) != JVM_SIGNATURE_FUNC) { - throwIllegalSignature("Method", name, signature, CHECK); + throwIllegalSignature("Method", name, signature, CHECK_0); } } // 4509014: If a class method name begins with '<', it must be "" @@ -629,7 +660,7 @@ name != vmSymbols::object_initializer_name()) { classfile_parse_error( "Bad method name at constant pool index %u in class file %s", - name_ref_index, CHECK); + name_ref_index, CHECK_0); } } break; @@ -651,13 +682,13 @@ if (name != vmSymbols::object_initializer_name()) { classfile_parse_error( "Bad constructor name at constant pool index %u in class file %s", - name_ref_index, CHECK); + name_ref_index, CHECK_0); } } else { if (name == vmSymbols::object_initializer_name()) { classfile_parse_error( "Bad method name at constant pool index %u in class file %s", - name_ref_index, CHECK); + name_ref_index, CHECK_0); } } break; @@ -669,7 +700,7 @@ case JVM_CONSTANT_MethodType: { const Symbol* const no_name = vmSymbols::type_name(); // place holder const Symbol* const signature = cp->method_type_signature_at(index); - verify_legal_method_signature(no_name, signature, CHECK); + verify_legal_method_signature(no_name, signature, CHECK_0); break; } case JVM_CONSTANT_Utf8: { @@ -677,6 +708,7 @@ } } // switch(tag) } // end of for + return 0; } void ClassFileParser::patch_constant_pool(ConstantPool* cp, @@ -3053,9 +3085,18 @@ } // Access flags jint flags; - // JVM_ACC_MODULE is defined in JDK-9 and later. + // JVM_ACC_MODULE is not allowed in JDK-9 and later. if (_major_version >= JAVA_9_VERSION) { flags = cfs->get_u2_fast() & (RECOGNIZED_INNER_CLASS_MODIFIERS | JVM_ACC_MODULE); + if ((flags & JVM_ACC_MODULE) != 0) { + ResourceMark rm(THREAD); + Exceptions::fthrow( + THREAD_AND_LOCATION, + vmSymbols::java_lang_NoClassDefFoundError(), + "%s is not a class because access_flag ACC_MODULE is set", + _class_name->as_C_string()); + return 0; + } } else { flags = cfs->get_u2_fast() & RECOGNIZED_INNER_CLASS_MODIFIERS; } @@ -4530,18 +4571,6 @@ // utility methods for format checking void ClassFileParser::verify_legal_class_modifiers(jint flags, TRAPS) const { - const bool is_module = (flags & JVM_ACC_MODULE) != 0; - assert(_major_version >= JAVA_9_VERSION || !is_module, "JVM_ACC_MODULE should not be set"); - if (is_module) { - ResourceMark rm(THREAD); - Exceptions::fthrow( - THREAD_AND_LOCATION, - vmSymbols::java_lang_NoClassDefFoundError(), - "%s is not a class because access_flag ACC_MODULE is set", - _class_name->as_C_string()); - return; - } - if (!_need_verify) { return; } const bool is_interface = (flags & JVM_ACC_INTERFACE) != 0; @@ -4550,8 +4579,12 @@ const bool is_super = (flags & JVM_ACC_SUPER) != 0; const bool is_enum = (flags & JVM_ACC_ENUM) != 0; const bool is_annotation = (flags & JVM_ACC_ANNOTATION) != 0; + const bool is_module = (flags & JVM_ACC_MODULE) != 0; const bool major_gte_15 = _major_version >= JAVA_1_5_VERSION; + assert(!(_major_version >= JAVA_9_VERSION && is_module), + "ACC_MODULE should not be set in class file whose version >= 53"); + if ((is_abstract && is_final) || (is_interface && !is_abstract) || (is_interface && major_gte_15 && (is_super || is_enum)) || @@ -5742,7 +5775,7 @@ ConstantPool* const cp = _cp; - parse_constant_pool(stream, cp, cp_size, CHECK); + int cp_result = parse_constant_pool(stream, cp, cp_size, CHECK); assert(cp_size == (const u2)cp->length(), "invariant"); @@ -5751,9 +5784,23 @@ // Access flags jint flags; - // JVM_ACC_MODULE is defined in JDK-9 and later. + // JVM_ACC_MODULE is not allowed in JDK-9 and later. if (_major_version >= JAVA_9_VERSION) { flags = stream->get_u2_fast() & (JVM_RECOGNIZED_CLASS_MODIFIERS | JVM_ACC_MODULE); + if ((flags & JVM_ACC_MODULE) != 0) { + ResourceMark rm(THREAD); + Exceptions::fthrow( + THREAD_AND_LOCATION, + vmSymbols::java_lang_NoClassDefFoundError(), + "%s is not a class because access_flag ACC_MODULE is set", + _class_name->as_C_string()); + return; + } else if (cp_result != 0) { + // Found a bad constant pool item and ACC_MODULE was not set so go ahead + // and throw a CFE. + classfile_parse_error("Unknown constant tag %u in class file %s", cp_result, CHECK); + return; + } } else { flags = stream->get_u2_fast() & JVM_RECOGNIZED_CLASS_MODIFIERS; } @@ -5763,10 +5810,9 @@ flags |= JVM_ACC_ABSTRACT; } - verify_legal_class_modifiers(flags, CHECK); - _access_flags.set_flags(flags); + verify_legal_class_modifiers((jint)_access_flags.as_int(), CHECK); // This class and superclass _this_class_index = stream->get_u2_fast();