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