8340177: Malformed system classes loaded by bootloader crash the JVM in product builds

Reviewed-by: coleenp, mli
This commit is contained in:
David Holmes 2024-10-23 21:39:26 +00:00
parent 98403b75df
commit 28d23ada6d
2 changed files with 59 additions and 114 deletions
src/hotspot/share/classfile

@ -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) {

@ -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,