8010319: Implementation of JEP 181: Nest-Based Access Control

Co-authored-by: Alex Buckley <alex.buckley@oracle.com>
Co-authored-by: Maurizio Mimadamore <maurizio.mimadamore@oracle.com>
Co-authored-by: Mandy Chung <mandy.chung@oracle.com>
Co-authored-by: Tobias Hartmann <tobias.hartmann@oracle.com>
Co-authored-by: Vlaidmir Ivanov <vladimir.x.ivanov@oracle.com>
Co-authored-by: Karen Kinnear <karen.kinnear@oracle.com>
Co-authored-by: Vladimir Kozlov <vladimir.kozlov@oracle.com>
Co-authored-by: John Rose <john.r.rose@oracle.com>
Co-authored-by: Daniel Smith <daniel.smith@oracle.com>
Co-authored-by: Serguei Spitsyn <serguei.spitsyn@oracle.com>
Co-authored-by: Kumar Srinivasan <kumardotsrinivasan@gmail.com>
Co-authored-by: Boris Ulasevich <boris.ulasevich@bell-sw.com>
Reviewed-by: alanb, psandoz, mchung, coleenp, acorn, mcimadamore, forax, jlahoda, sspitsyn, abuckley
This commit is contained in:
David Holmes 2018-06-23 01:32:41 -04:00
parent 6e0bd36f42
commit 95bf19563b
259 changed files with 21354 additions and 890 deletions

View file

@ -3148,7 +3148,6 @@ u2 ClassFileParser::parse_classfile_inner_classes_attribute(const ClassFileStrea
_inner_classes = inner_classes;
int index = 0;
const int cp_size = _cp->length();
cfs->guarantee_more(8 * length, CHECK_0); // 4-tuples of u2
for (int n = 0; n < length; n++) {
// Inner class index
@ -3222,6 +3221,38 @@ u2 ClassFileParser::parse_classfile_inner_classes_attribute(const ClassFileStrea
return length;
}
u2 ClassFileParser::parse_classfile_nest_members_attribute(const ClassFileStream* const cfs,
const u1* const nest_members_attribute_start,
TRAPS) {
const u1* const current_mark = cfs->current();
u2 length = 0;
if (nest_members_attribute_start != NULL) {
cfs->set_current(nest_members_attribute_start);
cfs->guarantee_more(2, CHECK_0); // length
length = cfs->get_u2_fast();
}
const int size = length;
Array<u2>* const nest_members = MetadataFactory::new_array<u2>(_loader_data, size, CHECK_0);
_nest_members = nest_members;
int index = 0;
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(
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);
nest_members->at_put(index++, class_info_index);
}
assert(index == size, "wrong size");
// Restore buffer's current position.
cfs->set_current(current_mark);
return length;
}
void ClassFileParser::parse_classfile_synthetic_attribute(TRAPS) {
set_class_synthetic_flag(true);
}
@ -3329,10 +3360,14 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
// Set inner classes attribute to default sentinel
_inner_classes = Universe::the_empty_short_array();
// Set nest members attribute to default sentinel
_nest_members = Universe::the_empty_short_array();
cfs->guarantee_more(2, CHECK); // attributes_count
u2 attributes_count = cfs->get_u2_fast();
bool parsed_sourcefile_attribute = false;
bool parsed_innerclasses_attribute = false;
bool parsed_nest_members_attribute = false;
bool parsed_nest_host_attribute = false;
bool parsed_enclosingmethod_attribute = false;
bool parsed_bootstrap_methods_attribute = false;
const u1* runtime_visible_annotations = NULL;
@ -3350,6 +3385,9 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
u4 inner_classes_attribute_length = 0;
u2 enclosing_method_class_index = 0;
u2 enclosing_method_method_index = 0;
const u1* nest_members_attribute_start = NULL;
u4 nest_members_attribute_length = 0;
// Iterate over attributes
while (attributes_count--) {
cfs->guarantee_more(6, CHECK); // attribute_name_index, attribute_length
@ -3498,6 +3536,40 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
assert(runtime_invisible_type_annotations != NULL, "null invisible type annotations");
}
cfs->skip_u1(attribute_length, CHECK);
} else if (_major_version >= JAVA_11_VERSION) {
if (tag == vmSymbols::tag_nest_members()) {
// Check for NestMembers tag
if (parsed_nest_members_attribute) {
classfile_parse_error("Multiple NestMembers attributes in class file %s", CHECK);
} else {
parsed_nest_members_attribute = true;
}
if (parsed_nest_host_attribute) {
classfile_parse_error("Conflicting NestHost and NestMembers attributes in class file %s", CHECK);
}
nest_members_attribute_start = cfs->current();
nest_members_attribute_length = attribute_length;
cfs->skip_u1(nest_members_attribute_length, CHECK);
} else if (tag == vmSymbols::tag_nest_host()) {
if (parsed_nest_host_attribute) {
classfile_parse_error("Multiple NestHost attributes in class file %s", CHECK);
} else {
parsed_nest_host_attribute = true;
}
if (parsed_nest_members_attribute) {
classfile_parse_error("Conflicting NestMembers and NestHost attributes in class file %s", CHECK);
}
if (_need_verify) {
guarantee_property(attribute_length == 2, "Wrong NestHost attribute length in class file %s", CHECK);
}
cfs->guarantee_more(2, CHECK);
u2 class_info_index = cfs->get_u2_fast();
check_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);
_nest_host = class_info_index;
}
} else {
// Unknown attribute
cfs->skip_u1(attribute_length, CHECK);
@ -3526,13 +3598,25 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf
enclosing_method_class_index,
enclosing_method_method_index,
CHECK);
if (parsed_innerclasses_attribute &&_need_verify && _major_version >= JAVA_1_5_VERSION) {
if (parsed_innerclasses_attribute && _need_verify && _major_version >= JAVA_1_5_VERSION) {
guarantee_property(
inner_classes_attribute_length == sizeof(num_of_classes) + 4 * sizeof(u2) * num_of_classes,
"Wrong InnerClasses attribute length in class file %s", CHECK);
}
}
if (parsed_nest_members_attribute) {
const u2 num_of_classes = parse_classfile_nest_members_attribute(
cfs,
nest_members_attribute_start,
CHECK);
if (_need_verify) {
guarantee_property(
nest_members_attribute_length == sizeof(num_of_classes) + sizeof(u2) * num_of_classes,
"Wrong NestMembers attribute length in class file %s", CHECK);
}
}
if (_max_bootstrap_specifier_index >= 0) {
guarantee_property(parsed_bootstrap_methods_attribute,
"Missing BootstrapMethods attribute in class file %s", CHECK);
@ -3595,6 +3679,8 @@ void ClassFileParser::apply_parsed_class_metadata(
this_klass->set_fields(_fields, java_fields_count);
this_klass->set_methods(_methods);
this_klass->set_inner_classes(_inner_classes);
this_klass->set_nest_members(_nest_members);
this_klass->set_nest_host_index(_nest_host);
this_klass->set_local_interfaces(_local_interfaces);
this_klass->set_annotations(_combined_annotations);
// Delay the setting of _transitive_interfaces until after initialize_supers() in
@ -4605,24 +4691,26 @@ static void check_final_method_override(const InstanceKlass* this_klass, TRAPS)
}
if (super_m->is_final() && !super_m->is_static() &&
// matching method in super is final, and not static
(Reflection::verify_field_access(this_klass,
super_m->method_holder(),
super_m->method_holder(),
super_m->access_flags(), false))
// this class can access super final method and therefore override
) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_VerifyError(),
"class %s overrides final method %s.%s%s",
this_klass->external_name(),
super_m->method_holder()->external_name(),
name->as_C_string(),
signature->as_C_string()
);
return;
!super_m->access_flags().is_private()) {
// matching method in super is final, and not static or private
bool can_access = Reflection::verify_member_access(this_klass,
super_m->method_holder(),
super_m->method_holder(),
super_m->access_flags(),
false, false, CHECK);
if (can_access) {
// this class can access super final method and therefore override
ResourceMark rm(THREAD);
Exceptions::fthrow(THREAD_AND_LOCATION,
vmSymbols::java_lang_VerifyError(),
"class %s overrides final method %s.%s%s",
this_klass->external_name(),
super_m->method_holder()->external_name(),
name->as_C_string(),
signature->as_C_string()
);
return;
}
}
// continue to look from super_m's holder's super.
@ -5470,6 +5558,7 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loa
assert(NULL == _fields, "invariant");
assert(NULL == _methods, "invariant");
assert(NULL == _inner_classes, "invariant");
assert(NULL == _nest_members, "invariant");
assert(NULL == _local_interfaces, "invariant");
assert(NULL == _combined_annotations, "invariant");
@ -5739,6 +5828,8 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
_fields(NULL),
_methods(NULL),
_inner_classes(NULL),
_nest_members(NULL),
_nest_host(0),
_local_interfaces(NULL),
_transitive_interfaces(NULL),
_combined_annotations(NULL),
@ -5843,6 +5934,7 @@ void ClassFileParser::clear_class_metadata() {
_fields = NULL;
_methods = NULL;
_inner_classes = NULL;
_nest_members = NULL;
_local_interfaces = NULL;
_combined_annotations = NULL;
_annotations = _type_annotations = NULL;
@ -5868,6 +5960,10 @@ ClassFileParser::~ClassFileParser() {
MetadataFactory::free_array<u2>(_loader_data, _inner_classes);
}
if (_nest_members != NULL && _nest_members != Universe::the_empty_short_array()) {
MetadataFactory::free_array<u2>(_loader_data, _nest_members);
}
// Free interfaces
InstanceKlass::deallocate_interfaces(_loader_data, _super_klass,
_local_interfaces, _transitive_interfaces);