< prev index next >

src/share/vm/classfile/classFileParser.cpp

Print this page

        

*** 103,119 **** // Extension method support. #define JAVA_8_VERSION 52 #define JAVA_9_VERSION 53 ! void ClassFileParser::parse_constant_pool_entries(const ClassFileStream* const stream, ConstantPool* cp, const int length, TRAPS) { assert(stream != NULL, "invariant"); assert(cp != NULL, "invariant"); // 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 // stream() when this function returns. DON'T call another method within // this method that uses stream(). --- 103,128 ---- // Extension method support. #define JAVA_8_VERSION 52 #define JAVA_9_VERSION 53 ! 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 // stream() when this function returns. DON'T call another method within // this method that uses stream().
*** 136,192 **** // for the following tag or the access_flags following constant pool, // so we don't need bounds-check for reading tag. const u1 tag = cfs->get_u1_fast(); switch (tag) { case JVM_CONSTANT_Class : { ! cfs->guarantee_more(3, CHECK); // 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 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 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 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 const u2 string_index = cfs->get_u2_fast(); cp->string_index_at_put(index, string_index); break; } case JVM_CONSTANT_MethodHandle : case JVM_CONSTANT_MethodType: { 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); } if (tag == JVM_CONSTANT_MethodHandle) { ! cfs->guarantee_more(4, CHECK); // 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 const u2 signature_index = cfs->get_u2_fast(); cp->method_type_index_at_put(index, signature_index); } else { ShouldNotReachHere(); --- 145,201 ---- // for the following tag or the access_flags following constant pool, // so we don't need bounds-check for reading tag. const u1 tag = cfs->get_u1_fast(); switch (tag) { case JVM_CONSTANT_Class : { ! 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_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_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_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_0); // string_index, tag/access_flags const u2 string_index = cfs->get_u2_fast(); cp->string_index_at_put(index, string_index); break; } case JVM_CONSTANT_MethodHandle : case JVM_CONSTANT_MethodType: { 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_0); } if (tag == JVM_CONSTANT_MethodHandle) { ! 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_0); // signature_index, tag/access_flags const u2 signature_index = cfs->get_u2_fast(); cp->method_type_index_at_put(index, signature_index); } else { ShouldNotReachHere();
*** 195,278 **** } case JVM_CONSTANT_InvokeDynamic : { 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); } ! cfs->guarantee_more(5, CHECK); // 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) { _max_bootstrap_specifier_index = (int) bootstrap_specifier_index; // collect for later } cp->invoke_dynamic_at_put(index, bootstrap_specifier_index, name_and_type_index); break; } case JVM_CONSTANT_Integer: { ! cfs->guarantee_more(5, CHECK); // 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 const u4 bytes = cfs->get_u4_fast(); cp->float_at_put(index, *(jfloat*)&bytes); break; } case JVM_CONSTANT_Long: { // A mangled type might cause you to overrun allocated memory 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 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 break; } case JVM_CONSTANT_Double: { // A mangled type might cause you to overrun allocated memory 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 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 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 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->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); } if (has_cp_patch_at(index)) { Handle patch = clear_cp_patch_at(index); guarantee_property(java_lang_String::is_instance(patch()), "Illegal utf8 patch at %d in class file %s", index, ! CHECK); 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; utf8_length = (int) strlen(str); } --- 204,287 ---- } case JVM_CONSTANT_InvokeDynamic : { 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_0); } ! 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) { _max_bootstrap_specifier_index = (int) bootstrap_specifier_index; // collect for later } cp->invoke_dynamic_at_put(index, bootstrap_specifier_index, name_and_type_index); break; } case JVM_CONSTANT_Integer: { ! 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_0); // bytes, tag/access_flags const u4 bytes = cfs->get_u4_fast(); cp->float_at_put(index, *(jfloat*)&bytes); break; } case JVM_CONSTANT_Long: { // A mangled type might cause you to overrun allocated memory guarantee_property(index + 1 < length, "Invalid constant pool entry %u in class file %s", index, ! 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 break; } case JVM_CONSTANT_Double: { // A mangled type might cause you to overrun allocated memory guarantee_property(index+1 < length, "Invalid constant pool entry %u in class file %s", index, ! 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_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_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_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_0); } if (has_cp_patch_at(index)) { Handle patch = clear_cp_patch_at(index); guarantee_property(java_lang_String::is_instance(patch()), "Illegal utf8 patch at %d in class file %s", index, ! 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; utf8_length = (int) strlen(str); }
*** 292,313 **** names_count, names, lengths, indices, hashValues, ! CHECK); names_count = 0; } } else { cp->symbol_at_put(index, result); } break; } default: { classfile_parse_error("Unknown constant tag %u in class file %s", tag, ! CHECK); break; } } // end of switch(tag) } // end of for --- 301,334 ---- names_count, names, lengths, indices, hashValues, ! CHECK_0); names_count = 0; } } else { cp->symbol_at_put(index, result); } 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_0); break; } } // end of switch(tag) } // end of for
*** 318,334 **** names_count, names, lengths, indices, hashValues, ! CHECK); } // Copy _current pointer of local copy back to stream. assert(stream->current() == old_current, "non-exclusive use of stream"); stream->set_current(cfs1.current()); } static inline bool valid_cp_range(int index, int length) { return (index > 0 && index < length); } --- 339,356 ---- names_count, names, lengths, indices, hashValues, ! 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) { return (index > 0 && index < length); }
*** 356,374 **** fatal(msg, index, _class_name->as_C_string()); } PRAGMA_DIAG_POP #endif ! void 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 index = 1; // declared outside of loops for portability // first verification pass - validate cross references // and fixup class and string constants --- 378,405 ---- fatal(msg, index, _class_name->as_C_string()); } PRAGMA_DIAG_POP #endif ! 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 ! 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 // first verification pass - validate cross references // and fixup class and string constants
*** 387,401 **** if (!_need_verify) break; const int klass_ref_index = cp->klass_ref_index_at(index); 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); 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); break; } case JVM_CONSTANT_String: { ShouldNotReachHere(); // Only JVM_CONSTANT_StringIndex should be present break; --- 418,432 ---- if (!_need_verify) break; const int klass_ref_index = cp->klass_ref_index_at(index); 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_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_0); break; } case JVM_CONSTANT_String: { ShouldNotReachHere(); // Only JVM_CONSTANT_StringIndex should be present break;
*** 408,430 **** case JVM_CONSTANT_Double: { index++; check_property( (index < length && cp->tag_at(index).is_invalid()), "Improper constant pool long/double index %u in class file %s", ! index, CHECK); break; } case JVM_CONSTANT_NameAndType: { if (!_need_verify) break; const int name_ref_index = cp->name_ref_index_at(index); 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); check_property(valid_symbol_at(signature_ref_index), "Invalid constant pool index %u in class file %s", ! signature_ref_index, CHECK); break; } case JVM_CONSTANT_Utf8: break; case JVM_CONSTANT_UnresolvedClass: // fall-through --- 439,461 ---- case JVM_CONSTANT_Double: { index++; check_property( (index < length && cp->tag_at(index).is_invalid()), "Improper constant pool long/double index %u in class file %s", ! index, CHECK_0); break; } case JVM_CONSTANT_NameAndType: { if (!_need_verify) break; const int name_ref_index = cp->name_ref_index_at(index); 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_0); check_property(valid_symbol_at(signature_ref_index), "Invalid constant pool index %u in class file %s", ! signature_ref_index, CHECK_0); break; } case JVM_CONSTANT_Utf8: break; case JVM_CONSTANT_UnresolvedClass: // fall-through
*** 434,461 **** } case JVM_CONSTANT_ClassIndex: { 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); cp->unresolved_klass_at_put(index, cp->symbol_at(class_index)); break; } case JVM_CONSTANT_StringIndex: { 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); Symbol* const sym = cp->symbol_at(string_index); cp->unresolved_string_at_put(index, sym); break; } case JVM_CONSTANT_MethodHandle: { 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); const constantTag tag = cp->tag_at(ref_index); const int ref_kind = cp->method_handle_ref_kind_at(index); switch (ref_kind) { case JVM_REF_getField: --- 465,492 ---- } case JVM_CONSTANT_ClassIndex: { 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_0); cp->unresolved_klass_at_put(index, cp->symbol_at(class_index)); break; } case JVM_CONSTANT_StringIndex: { 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_0); Symbol* const sym = cp->symbol_at(string_index); cp->unresolved_string_at_put(index, sym); break; } case JVM_CONSTANT_MethodHandle: { 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_0); const constantTag tag = cp->tag_at(ref_index); const int ref_kind = cp->method_handle_ref_kind_at(index); switch (ref_kind) { case JVM_REF_getField:
*** 463,523 **** case JVM_REF_putField: case JVM_REF_putStatic: { check_property( tag.is_field(), "Invalid constant pool index %u in class file %s (not a field)", ! ref_index, CHECK); break; } case JVM_REF_invokeVirtual: case JVM_REF_newInvokeSpecial: { check_property( tag.is_method(), "Invalid constant pool index %u in class file %s (not a method)", ! ref_index, CHECK); break; } case JVM_REF_invokeStatic: case JVM_REF_invokeSpecial: { check_property( 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); 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); break; } default: { classfile_parse_error( "Bad method handle kind at constant pool index %u in class file %s", ! index, CHECK); } } // switch(refkind) // Keep the ref_index unchanged. It will be indirected at link-time. break; } // case MethodHandle case JVM_CONSTANT_MethodType: { 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); break; } case JVM_CONSTANT_InvokeDynamic: { const int name_and_type_ref_index = cp->invoke_dynamic_name_and_type_ref_index_at(index); 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); // bootstrap specifier index must be checked later, // when BootstrapMethods attr is available break; } default: { --- 494,554 ---- case JVM_REF_putField: case JVM_REF_putStatic: { check_property( tag.is_field(), "Invalid constant pool index %u in class file %s (not a field)", ! ref_index, CHECK_0); break; } case JVM_REF_invokeVirtual: case JVM_REF_newInvokeSpecial: { check_property( tag.is_method(), "Invalid constant pool index %u in class file %s (not a method)", ! ref_index, CHECK_0); break; } case JVM_REF_invokeStatic: case JVM_REF_invokeSpecial: { check_property( 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_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_0); break; } default: { classfile_parse_error( "Bad method handle kind at constant pool index %u in class file %s", ! index, CHECK_0); } } // switch(refkind) // Keep the ref_index unchanged. It will be indirected at link-time. break; } // case MethodHandle case JVM_CONSTANT_MethodType: { 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_0); break; } case JVM_CONSTANT_InvokeDynamic: { const int name_and_type_ref_index = cp->invoke_dynamic_name_and_type_ref_index_at(index); 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_0); // bootstrap specifier index must be checked later, // when BootstrapMethods attr is available break; } default: {
*** 530,592 **** if (_cp_patches != NULL) { // need to treat this_class specially... int this_class_index; { ! stream->guarantee_more(8, CHECK); // 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(); stream->set_current(mark); // revert to mark } for (index = 1; index < length; index++) { // Index 0 is unused 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); } } } if (!_need_verify) { ! return; } // second verification pass - checks the strings are of the right format. // but not yet to the other entries for (index = 1; index < length; index++) { const jbyte tag = cp->tag_at(index).value(); switch (tag) { 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); break; } case JVM_CONSTANT_NameAndType: { if (_need_verify) { const int sig_index = cp->signature_ref_index_at(index); const int name_index = cp->name_ref_index_at(index); const Symbol* const name = cp->symbol_at(name_index); 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); guarantee_property(name->utf8_length() != 0, "Illegal zero length constant pool entry at %d in class %s", ! name_index, CHECK); 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); } else { // Format check field name and signature ! verify_legal_field_name(name, CHECK); ! verify_legal_field_signature(name, sig, CHECK); } } break; } case JVM_CONSTANT_InvokeDynamic: --- 561,623 ---- if (_cp_patches != NULL) { // need to treat this_class specially... int this_class_index; { ! 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(); stream->set_current(mark); // revert to mark } for (index = 1; index < length; index++) { // Index 0 is unused 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_0); ! patch_constant_pool(cp, index, cp_patch_at(index), CHECK_0); } } } if (!_need_verify) { ! return 0; } // second verification pass - checks the strings are of the right format. // but not yet to the other entries for (index = 1; index < length; index++) { const jbyte tag = cp->tag_at(index).value(); switch (tag) { 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_0); break; } case JVM_CONSTANT_NameAndType: { if (_need_verify) { const int sig_index = cp->signature_ref_index_at(index); const int name_index = cp->name_ref_index_at(index); const Symbol* const name = cp->symbol_at(name_index); 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_0); guarantee_property(name->utf8_length() != 0, "Illegal zero length constant pool entry at %d in class %s", ! name_index, CHECK_0); if (sig->byte_at(0) == JVM_SIGNATURE_FUNC) { // Format check method name and signature ! 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_0); ! verify_legal_field_signature(name, sig, CHECK_0); } } break; } case JVM_CONSTANT_InvokeDynamic:
*** 607,637 **** if (_need_verify) { // Field name and signature are verified above, when iterating NameAndType_info. // 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); } } } else { if (_need_verify) { // Method name and signature are verified above, when iterating NameAndType_info. // 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); } } // 4509014: If a class method name begins with '<', it must be "<init>" const unsigned int name_len = name->utf8_length(); if (tag == JVM_CONSTANT_Methodref && name_len != 0 && name->byte_at(0) == '<' && name != vmSymbols::object_initializer_name()) { classfile_parse_error( "Bad method name at constant pool index %u in class file %s", ! name_ref_index, CHECK); } } break; } case JVM_CONSTANT_MethodHandle: { --- 638,668 ---- if (_need_verify) { // Field name and signature are verified above, when iterating NameAndType_info. // 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_0); } } } else { if (_need_verify) { // Method name and signature are verified above, when iterating NameAndType_info. // 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_0); } } // 4509014: If a class method name begins with '<', it must be "<init>" const unsigned int name_len = name->utf8_length(); if (tag == JVM_CONSTANT_Methodref && name_len != 0 && name->byte_at(0) == '<' && name != vmSymbols::object_initializer_name()) { classfile_parse_error( "Bad method name at constant pool index %u in class file %s", ! name_ref_index, CHECK_0); } } break; } case JVM_CONSTANT_MethodHandle: {
*** 649,665 **** const Symbol* const name = cp->symbol_at(name_ref_index); if (ref_kind == JVM_REF_newInvokeSpecial) { 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); } } 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); } } break; } // Other ref_kinds are already fully checked in previous pass. --- 680,696 ---- const Symbol* const name = cp->symbol_at(name_ref_index); if (ref_kind == JVM_REF_newInvokeSpecial) { 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_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_0); } } break; } // Other ref_kinds are already fully checked in previous pass.
*** 667,684 **** break; } 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); break; } case JVM_CONSTANT_Utf8: { assert(cp->symbol_at(index)->refcount() != 0, "count corrupted"); } } // switch(tag) } // end of for } void ClassFileParser::patch_constant_pool(ConstantPool* cp, int index, Handle patch, --- 698,716 ---- break; } 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_0); break; } case JVM_CONSTANT_Utf8: { assert(cp->symbol_at(index)->refcount() != 0, "count corrupted"); } } // switch(tag) } // end of for + return 0; } void ClassFileParser::patch_constant_pool(ConstantPool* cp, int index, Handle patch,
*** 3051,3063 **** guarantee_property(inner_class_info_index != outer_class_info_index, "Class is both outer and inner class in class file %s", CHECK_0); } // Access flags jint flags; ! // JVM_ACC_MODULE is defined in JDK-9 and later. if (_major_version >= JAVA_9_VERSION) { flags = cfs->get_u2_fast() & (RECOGNIZED_INNER_CLASS_MODIFIERS | JVM_ACC_MODULE); } else { flags = cfs->get_u2_fast() & RECOGNIZED_INNER_CLASS_MODIFIERS; } if ((flags & JVM_ACC_INTERFACE) && _major_version < JAVA_6_VERSION) { // Set abstract bit for old class files for backward compatibility --- 3083,3104 ---- guarantee_property(inner_class_info_index != outer_class_info_index, "Class is both outer and inner class in class file %s", CHECK_0); } // Access flags jint flags; ! // 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; } if ((flags & JVM_ACC_INTERFACE) && _major_version < JAVA_6_VERSION) { // Set abstract bit for old class files for backward compatibility
*** 4528,4559 **** } // 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; const bool is_abstract = (flags & JVM_ACC_ABSTRACT) != 0; const bool is_final = (flags & JVM_ACC_FINAL) != 0; 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 major_gte_15 = _major_version >= JAVA_1_5_VERSION; if ((is_abstract && is_final) || (is_interface && !is_abstract) || (is_interface && major_gte_15 && (is_super || is_enum)) || (!is_interface && major_gte_15 && is_annotation)) { ResourceMark rm(THREAD); --- 4569,4592 ---- } // utility methods for format checking void ClassFileParser::verify_legal_class_modifiers(jint flags, TRAPS) const { if (!_need_verify) { return; } const bool is_interface = (flags & JVM_ACC_INTERFACE) != 0; const bool is_abstract = (flags & JVM_ACC_ABSTRACT) != 0; const bool is_final = (flags & JVM_ACC_FINAL) != 0; 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)) || (!is_interface && major_gte_15 && is_annotation)) { ResourceMark rm(THREAD);
*** 5740,5774 **** cp_size, CHECK); ConstantPool* const cp = _cp; ! parse_constant_pool(stream, cp, cp_size, CHECK); assert(cp_size == (const u2)cp->length(), "invariant"); // ACCESS FLAGS stream->guarantee_more(8, CHECK); // flags, this_class, super_class, infs_len // Access flags jint flags; ! // JVM_ACC_MODULE is defined in JDK-9 and later. if (_major_version >= JAVA_9_VERSION) { flags = stream->get_u2_fast() & (JVM_RECOGNIZED_CLASS_MODIFIERS | JVM_ACC_MODULE); } else { flags = stream->get_u2_fast() & JVM_RECOGNIZED_CLASS_MODIFIERS; } if ((flags & JVM_ACC_INTERFACE) && _major_version < JAVA_6_VERSION) { // Set abstract bit for old class files for backward compatibility flags |= JVM_ACC_ABSTRACT; } - verify_legal_class_modifiers(flags, CHECK); - _access_flags.set_flags(flags); // This class and superclass _this_class_index = stream->get_u2_fast(); check_property( valid_cp_range(_this_class_index, cp_size) && --- 5773,5820 ---- cp_size, CHECK); ConstantPool* const cp = _cp; ! int cp_result = parse_constant_pool(stream, cp, cp_size, CHECK); assert(cp_size == (const u2)cp->length(), "invariant"); // ACCESS FLAGS stream->guarantee_more(8, CHECK); // flags, this_class, super_class, infs_len // Access flags jint flags; ! // 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; } if ((flags & JVM_ACC_INTERFACE) && _major_version < JAVA_6_VERSION) { // Set abstract bit for old class files for backward compatibility flags |= JVM_ACC_ABSTRACT; } _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(); check_property( valid_cp_range(_this_class_index, cp_size) &&
< prev index next >