From 28d23ada6dde007ed60b8538cc159afc62d76db3 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Wed, 23 Oct 2024 21:39:26 +0000 Subject: [PATCH] 8340177: Malformed system classes loaded by bootloader crash the JVM in product builds Reviewed-by: coleenp, mli --- .../share/classfile/classFileParser.cpp | 135 ++++++++---------- .../share/classfile/classFileParser.hpp | 38 ----- 2 files changed, 59 insertions(+), 114 deletions(-) diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 0fb8d54233c..dd7cecdd9c2 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -411,23 +411,6 @@ static inline Symbol* check_symbol_at(const ConstantPool* cp, int index) { return nullptr; } -#ifdef ASSERT -PRAGMA_DIAG_PUSH -PRAGMA_FORMAT_NONLITERAL_IGNORED -void ClassFileParser::report_assert_property_failure(const char* msg, TRAPS) const { - ResourceMark rm(THREAD); - fatal(msg, _class_name->as_C_string()); -} - -void ClassFileParser::report_assert_property_failure(const char* msg, - int index, - TRAPS) const { - ResourceMark rm(THREAD); - 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, @@ -462,10 +445,10 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, if (!_need_verify) break; const int klass_ref_index = cp->uncached_klass_ref_index_at(index); const int name_and_type_ref_index = cp->uncached_name_and_type_ref_index_at(index); - check_property(valid_klass_reference_at(klass_ref_index), + guarantee_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) && + guarantee_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); @@ -482,7 +465,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, case JVM_CONSTANT_Long: case JVM_CONSTANT_Double: { index++; - check_property( + guarantee_property( (index < length && cp->tag_at(index).is_invalid()), "Improper constant pool long/double index %u in class file %s", index, CHECK); @@ -492,10 +475,10 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, 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), + guarantee_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), + guarantee_property(valid_symbol_at(signature_ref_index), "Invalid constant pool index %u in class file %s", signature_ref_index, CHECK); break; @@ -509,7 +492,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, } case JVM_CONSTANT_ClassIndex: { const int class_index = cp->klass_index_at(index); - check_property(valid_symbol_at(class_index), + guarantee_property(valid_symbol_at(class_index), "Invalid constant pool index %u in class file %s", class_index, CHECK); cp->unresolved_klass_at_put(index, class_index, num_klasses++); @@ -517,7 +500,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, } case JVM_CONSTANT_StringIndex: { const int string_index = cp->string_index_at(index); - check_property(valid_symbol_at(string_index), + guarantee_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); @@ -526,7 +509,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, } case JVM_CONSTANT_MethodHandle: { const int ref_index = cp->method_handle_index_at(index); - check_property(valid_cp_range(ref_index, length), + guarantee_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); @@ -537,7 +520,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, case JVM_REF_getStatic: case JVM_REF_putField: case JVM_REF_putStatic: { - check_property( + guarantee_property( tag.is_field(), "Invalid constant pool index %u in class file %s (not a field)", ref_index, CHECK); @@ -545,7 +528,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, } case JVM_REF_invokeVirtual: case JVM_REF_newInvokeSpecial: { - check_property( + guarantee_property( tag.is_method(), "Invalid constant pool index %u in class file %s (not a method)", ref_index, CHECK); @@ -553,7 +536,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, } case JVM_REF_invokeStatic: case JVM_REF_invokeSpecial: { - check_property( + guarantee_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)", @@ -561,7 +544,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, break; } case JVM_REF_invokeInterface: { - check_property( + guarantee_property( tag.is_interface_method(), "Invalid constant pool index %u in class file %s (not an interface method)", ref_index, CHECK); @@ -579,7 +562,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, } // case MethodHandle case JVM_CONSTANT_MethodType: { const int ref_index = cp->method_type_index_at(index); - check_property(valid_symbol_at(ref_index), + guarantee_property(valid_symbol_at(ref_index), "Invalid constant pool index %u in class file %s", ref_index, CHECK); break; @@ -588,7 +571,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, const int name_and_type_ref_index = cp->bootstrap_name_and_type_ref_index_at(index); - check_property(valid_cp_range(name_and_type_ref_index, length) && + guarantee_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); @@ -603,7 +586,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream, const int name_and_type_ref_index = cp->bootstrap_name_and_type_ref_index_at(index); - check_property(valid_cp_range(name_and_type_ref_index, length) && + guarantee_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); @@ -821,7 +804,7 @@ void ClassFileParser::parse_interfaces(const ClassFileStream* const stream, for (index = 0; index < itfs_len; index++) { const u2 interface_index = stream->get_u2(CHECK); Klass* interf; - check_property( + guarantee_property( valid_klass_reference_at(interface_index), "Interface name has bad constant pool index %u in class file %s", interface_index, CHECK); @@ -1255,10 +1238,10 @@ void ClassFileParser::parse_field_attributes(const ClassFileStream* const cfs, cfs->guarantee_more(6, CHECK); // attribute_name_index, attribute_length const u2 attribute_name_index = cfs->get_u2_fast(); const u4 attribute_length = cfs->get_u4_fast(); - check_property(valid_symbol_at(attribute_name_index), - "Invalid field attribute index %u in class file %s", - attribute_name_index, - CHECK); + guarantee_property(valid_symbol_at(attribute_name_index), + "Invalid field attribute index %u in class file %s", + attribute_name_index, + CHECK); const Symbol* const attribute_name = cp->symbol_at(attribute_name_index); if (is_static && attribute_name == vmSymbols::tag_constant_value()) { @@ -1267,7 +1250,7 @@ void ClassFileParser::parse_field_attributes(const ClassFileStream* const cfs, classfile_parse_error("Duplicate ConstantValue attribute in class file %s", THREAD); return; } - check_property( + guarantee_property( attribute_length == 2, "Invalid ConstantValue field attribute length %u in class file %s", attribute_length, CHECK); @@ -1413,14 +1396,14 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs, FieldInfo::FieldFlags fieldFlags(0); const u2 name_index = cfs->get_u2_fast(); - check_property(valid_symbol_at(name_index), + guarantee_property(valid_symbol_at(name_index), "Invalid constant pool index %u for field name in class file %s", name_index, CHECK); const Symbol* const name = cp->symbol_at(name_index); verify_legal_field_name(name, CHECK); const u2 signature_index = cfs->get_u2_fast(); - check_property(valid_symbol_at(signature_index), + guarantee_property(valid_symbol_at(signature_index), "Invalid constant pool index %u for field signature in class file %s", signature_index, CHECK); const Symbol* const sig = cp->symbol_at(signature_index); @@ -1598,7 +1581,7 @@ void ClassFileParser::parse_linenumber_table(u4 code_attribute_length, const unsigned int length_in_bytes = num_entries * (sizeof(u2) * 2); // Verify line number attribute and table length - check_property( + guarantee_property( code_attribute_length == sizeof(u2) + length_in_bytes, "LineNumberTable attribute has wrong length in class file %s", CHECK); @@ -1788,7 +1771,7 @@ const ClassFileParser::unsafe_u2* ClassFileParser::parse_checked_exceptions(cons cfs->guarantee_more(2 * len, CHECK_NULL); for (int i = 0; i < len; i++) { checked_exception = cfs->get_u2_fast(); - check_property( + guarantee_property( valid_klass_reference_at(checked_exception), "Exception name has bad type at constant pool %u in class file %s", checked_exception, CHECK_NULL); @@ -2137,7 +2120,7 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs, int flags = cfs->get_u2_fast(); const u2 name_index = cfs->get_u2_fast(); const int cp_size = cp->length(); - check_property( + guarantee_property( valid_symbol_at(name_index), "Illegal constant pool index %u for method name in class file %s", name_index, CHECK_NULL); @@ -2235,7 +2218,7 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs, cfs->guarantee_more(6, CHECK_NULL); // method_attribute_name_index, method_attribute_length const u2 method_attribute_name_index = cfs->get_u2_fast(); const u4 method_attribute_length = cfs->get_u4_fast(); - check_property( + guarantee_property( valid_symbol_at(method_attribute_name_index), "Invalid method attribute name index %u in class file %s", method_attribute_name_index, CHECK_NULL); @@ -2310,10 +2293,10 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs, calculated_attribute_length += code_attribute_length + (unsigned)sizeof(code_attribute_name_index) + (unsigned)sizeof(code_attribute_length); - check_property(valid_symbol_at(code_attribute_name_index), - "Invalid code attribute name index %u in class file %s", - code_attribute_name_index, - CHECK_NULL); + guarantee_property(valid_symbol_at(code_attribute_name_index), + "Invalid code attribute name index %u in class file %s", + code_attribute_name_index, + CHECK_NULL); if (LoadLineNumberTables && cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_line_number_table()) { // Parse and compress line number table @@ -2798,7 +2781,7 @@ u2 ClassFileParser::parse_generic_signature_attribute(const ClassFileStream* con cfs->guarantee_more(2, CHECK_0); // generic_signature_index const u2 generic_signature_index = cfs->get_u2_fast(); - check_property( + guarantee_property( valid_symbol_at(generic_signature_index), "Invalid Signature attribute at constant pool index %u in class file %s", generic_signature_index, CHECK_0); @@ -2812,7 +2795,7 @@ void ClassFileParser::parse_classfile_sourcefile_attribute(const ClassFileStream cfs->guarantee_more(2, CHECK); // sourcefile_index const u2 sourcefile_index = cfs->get_u2_fast(); - check_property( + guarantee_property( valid_symbol_at(sourcefile_index), "Invalid SourceFile attribute at constant pool index %u in class file %s", sourcefile_index, CHECK); @@ -2959,13 +2942,13 @@ u2 ClassFileParser::parse_classfile_inner_classes_attribute(const ClassFileStrea for (int n = 0; n < length; n++) { // Inner class index const u2 inner_class_info_index = cfs->get_u2_fast(); - check_property( + guarantee_property( valid_klass_reference_at(inner_class_info_index), "inner_class_info_index %u has bad constant type in class file %s", inner_class_info_index, CHECK_0); // Outer class index const u2 outer_class_info_index = cfs->get_u2_fast(); - check_property( + guarantee_property( outer_class_info_index == 0 || valid_klass_reference_at(outer_class_info_index), "outer_class_info_index %u has bad constant type in class file %s", @@ -2979,7 +2962,7 @@ u2 ClassFileParser::parse_classfile_inner_classes_attribute(const ClassFileStrea } // Inner class name const u2 inner_name_index = cfs->get_u2_fast(); - check_property( + guarantee_property( inner_name_index == 0 || valid_symbol_at(inner_name_index), "inner_name_index %u has bad constant type in class file %s", inner_name_index, CHECK_0); @@ -3055,7 +3038,7 @@ u2 ClassFileParser::parse_classfile_nest_members_attribute(const ClassFileStream cfs->guarantee_more(2 * length, CHECK_0); for (int n = 0; n < length; n++) { const u2 class_info_index = cfs->get_u2_fast(); - check_property( + guarantee_property( valid_klass_reference_at(class_info_index), "Nest member class_info_index %u has bad constant type in class file %s", class_info_index, CHECK_0); @@ -3088,7 +3071,7 @@ u2 ClassFileParser::parse_classfile_permitted_subclasses_attribute(const ClassFi cfs->guarantee_more(2 * length, CHECK_0); for (int n = 0; n < length; n++) { const u2 class_info_index = cfs->get_u2_fast(); - check_property( + guarantee_property( valid_klass_reference_at(class_info_index), "Permitted subclass class_info_index %u has bad constant type in class file %s", class_info_index, CHECK_0); @@ -3137,14 +3120,14 @@ u4 ClassFileParser::parse_classfile_record_attribute(const ClassFileStream* cons cfs->guarantee_more(6, CHECK_0); // name_index, descriptor_index, attributes_count const u2 name_index = cfs->get_u2_fast(); - check_property(valid_symbol_at(name_index), + guarantee_property(valid_symbol_at(name_index), "Invalid constant pool index %u for name in Record attribute in class file %s", name_index, CHECK_0); const Symbol* const name = cp->symbol_at(name_index); verify_legal_field_name(name, CHECK_0); const u2 descriptor_index = cfs->get_u2_fast(); - check_property(valid_symbol_at(descriptor_index), + guarantee_property(valid_symbol_at(descriptor_index), "Invalid constant pool index %u for descriptor in Record attribute in class file %s", descriptor_index, CHECK_0); const Symbol* const descr = cp->symbol_at(descriptor_index); @@ -3167,7 +3150,7 @@ u4 ClassFileParser::parse_classfile_record_attribute(const ClassFileStream* cons const u2 attribute_name_index = cfs->get_u2_fast(); const u4 attribute_length = cfs->get_u4_fast(); calculate_attr_size += 6; - check_property( + guarantee_property( valid_symbol_at(attribute_name_index), "Invalid Record attribute name index %u in class file %s", attribute_name_index, CHECK_0); @@ -3265,7 +3248,7 @@ void ClassFileParser::parse_classfile_signature_attribute(const ClassFileStream* assert(cfs != nullptr, "invariant"); const u2 signature_index = cfs->get_u2(CHECK); - check_property( + guarantee_property( valid_symbol_at(signature_index), "Invalid constant pool index %u in Signature attribute in class file %s", signature_index, CHECK); @@ -3323,7 +3306,7 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(const ClassFil cfs->guarantee_more(sizeof(u2) * 2, CHECK); // bsm, argc const u2 bootstrap_method_index = cfs->get_u2_fast(); const u2 argument_count = cfs->get_u2_fast(); - check_property( + guarantee_property( valid_cp_range(bootstrap_method_index, cp_size) && cp->tag_at(bootstrap_method_index).is_method_handle(), "bootstrap_method_index %u has bad constant type in class file %s", @@ -3340,7 +3323,7 @@ void ClassFileParser::parse_classfile_bootstrap_methods_attribute(const ClassFil cfs->guarantee_more(sizeof(u2) * argument_count, CHECK); // argv[argc] for (int j = 0; j < argument_count; j++) { const u2 argument_index = cfs->get_u2_fast(); - check_property( + guarantee_property( valid_cp_range(argument_index, cp_size) && cp->tag_at(argument_index).is_loadable_constant(), "argument_index %u has bad constant type in class file %s", @@ -3401,7 +3384,7 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf cfs->guarantee_more(6, CHECK); // attribute_name_index, attribute_length const u2 attribute_name_index = cfs->get_u2_fast(); const u4 attribute_length = cfs->get_u4_fast(); - check_property( + guarantee_property( valid_symbol_at(attribute_name_index), "Attribute name has bad constant pool index %u in class file %s", attribute_name_index, CHECK); @@ -3513,7 +3496,7 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf return; } // Validate the constant pool indices and types - check_property(valid_klass_reference_at(enclosing_method_class_index), + guarantee_property(valid_klass_reference_at(enclosing_method_class_index), "Invalid or out-of-bounds class index in EnclosingMethod attribute in class file %s", CHECK); if (enclosing_method_method_index != 0 && (!cp->is_within_bounds(enclosing_method_method_index) || @@ -3580,7 +3563,7 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf } cfs->guarantee_more(2, CHECK); u2 class_info_index = cfs->get_u2_fast(); - check_property( + guarantee_property( valid_klass_reference_at(class_info_index), "Nest-host class_info_index %u has bad constant type in class file %s", class_info_index, CHECK); @@ -3789,15 +3772,15 @@ const InstanceKlass* ClassFileParser::parse_super_class(ConstantPool* const cp, const InstanceKlass* super_klass = nullptr; if (super_class_index == 0) { - check_property(_class_name == vmSymbols::java_lang_Object(), - "Invalid superclass index %u in class file %s", - super_class_index, - CHECK_NULL); + guarantee_property(_class_name == vmSymbols::java_lang_Object(), + "Invalid superclass index %u in class file %s", + super_class_index, + CHECK_NULL); } else { - check_property(valid_klass_reference_at(super_class_index), - "Invalid superclass index %u in class file %s", - super_class_index, - CHECK_NULL); + guarantee_property(valid_klass_reference_at(super_class_index), + "Invalid superclass index %u in class file %s", + super_class_index, + CHECK_NULL); // The class name should be legal because it is checked when parsing constant pool. // However, make sure it is not an array type. bool is_array = false; @@ -5523,7 +5506,7 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream, // This class and superclass _this_class_index = stream->get_u2_fast(); - check_property( + guarantee_property( valid_cp_range(_this_class_index, cp_size) && cp->tag_at(_this_class_index).is_unresolved_klass(), "Invalid this class index %u in constant pool in class file %s", @@ -5704,9 +5687,9 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st assert(_loader_data != nullptr, "invariant"); if (_class_name == vmSymbols::java_lang_Object()) { - check_property(_local_interfaces == Universe::the_empty_instance_klass_array(), - "java.lang.Object cannot implement an interface in class file %s", - CHECK); + guarantee_property(_local_interfaces == Universe::the_empty_instance_klass_array(), + "java.lang.Object cannot implement an interface in class file %s", + CHECK); } // We check super class after class file is parsed and format is checked if (_super_class_index > 0 && nullptr == _super_klass) { diff --git a/src/hotspot/share/classfile/classFileParser.hpp b/src/hotspot/share/classfile/classFileParser.hpp index d32dd6d5f78..a8a388f8ded 100644 --- a/src/hotspot/share/classfile/classFileParser.hpp +++ b/src/hotspot/share/classfile/classFileParser.hpp @@ -378,44 +378,6 @@ class ClassFileParser { if (!b) { classfile_parse_error(msg, THREAD); return; } } - void report_assert_property_failure(const char* msg, TRAPS) const PRODUCT_RETURN; - void report_assert_property_failure(const char* msg, int index, TRAPS) const PRODUCT_RETURN; - - inline void assert_property(bool b, const char* msg, TRAPS) const { -#ifdef ASSERT - if (!b) { - report_assert_property_failure(msg, THREAD); - } -#endif - } - - inline void assert_property(bool b, const char* msg, int index, TRAPS) const { -#ifdef ASSERT - if (!b) { - report_assert_property_failure(msg, index, THREAD); - } -#endif - } - - inline void check_property(bool property, - const char* msg, - int index, - TRAPS) const { - if (_need_verify) { - guarantee_property(property, msg, index, CHECK); - } else { - assert_property(property, msg, index, CHECK); - } - } - - inline void check_property(bool property, const char* msg, TRAPS) const { - if (_need_verify) { - guarantee_property(property, msg, CHECK); - } else { - assert_property(property, msg, CHECK); - } - } - inline void guarantee_property(bool b, const char* msg, int index,