Skip to content
Permalink
Browse files
JDK-8243204 add class load time checking of abstract super classes of…
Reviewed-by: fparain
  • Loading branch information
Harold Seigel committed May 8, 2020
1 parent e586cdb commit b00578fa211759b749b2b4af8be0e2b6e8d2b9a0
Showing 17 changed files with 2,545 additions and 217 deletions.
@@ -947,6 +947,7 @@ static bool put_after_lookup(const Symbol* name, const Symbol* sig, NameSigHash*
void ClassFileParser::parse_interfaces(const ClassFileStream* stream,
int itfs_len,
ConstantPool* cp,
bool is_inline_type,
bool* const has_nonstatic_concrete_methods,
// FIXME: lots of these functions
// declare their parameters as const,
@@ -1003,6 +1004,18 @@ void ClassFileParser::parse_interfaces(const ClassFileStream* stream,
}

InstanceKlass* ik = InstanceKlass::cast(interf);
if (is_inline_type && ik->invalid_inline_super()) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_IncompatibleClassChangeError(),
"Inline type %s attempts to implement interface java.lang.IdentityObject",
_class_name->as_klass_external_name());
return;
}
if (ik->invalid_inline_super()) {
set_invalid_inline_super();
}
if (ik->has_nonstatic_concrete_methods()) {
*has_nonstatic_concrete_methods = true;
}
@@ -6031,7 +6044,6 @@ InstanceKlass* ClassFileParser::create_instance_klass(bool changed_by_loadhook,
InstanceKlass::allocate_instance_klass(*this, CHECK_NULL);

fill_instance_klass(ik, changed_by_loadhook, CHECK_NULL);

assert(_klass == ik, "invariant");


@@ -6062,6 +6074,41 @@ InstanceKlass* ClassFileParser::create_instance_klass(bool changed_by_loadhook,
return ik;
}

// Return true if the specified class is not a valid super class for an inline type.
// A valid super class for an inline type is abstract, has no instance fields,
// does not implement interface java.lang.IdentityObject (checked elsewhere), has
// an empty body-less no-arg constructor, and no synchronized instance methods.
// This function doesn't check if the class's super types are invalid. Those checks
// are done elsewhere. The final determination of whether or not a class is an
// invalid super type for an inline class is done in fill_instance_klass().
static bool is_invalid_super_for_inline_type(const InstanceKlass* ik) {
if (ik->name() == vmSymbols::java_lang_IdentityObject()) {
return true;
}
if (ik->is_interface() || ik->name() == vmSymbols::java_lang_Object()) {
return false;
}
if (!ik->is_abstract() || ik->has_nonstatic_fields()) {
return true;
} else {
Array<Method*>* methods = ik->methods();
// Look at each method.
for (int x = 0; x < methods->length(); x++) {
const Method* const method = methods->at(x);
if (method->is_synchronized() && !method->is_static()) {
return true;

} else if (method->name() == vmSymbols::object_initializer_name()) {
if (method->signature() != vmSymbols::void_method_signature() ||
!method->is_vanilla_constructor()) {
return true;
}
}
}
}
return false;
}

void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loadhook, TRAPS) {
assert(ik != NULL, "invariant");

@@ -6324,6 +6371,15 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loa
}
}

// Set ik->invalid_inline_super field to TRUE if already marked as invalid,
// if super is marked invalid, or if is_invalid_super_for_inline_type()
// returns true
if (invalid_inline_super() ||
(_super_klass != NULL && _super_klass->invalid_inline_super()) ||
is_invalid_super_for_inline_type(ik)) {
ik->set_invalid_inline_super();
}

JFR_ONLY(INIT_ID(ik);)

// If we reach here, all is well.
@@ -6480,6 +6536,8 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
_is_empty_value(false),
_is_naturally_atomic(false),
_is_declared_atomic(false),
_invalid_inline_super(false),
_invalid_identity_super(false),
_has_finalizer(false),
_has_empty_finalizer(false),
_has_vanilla_constructor(false),
@@ -6818,6 +6876,7 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
parse_interfaces(stream,
_itfs_len,
cp,
is_value_type(),
&_has_nonstatic_concrete_methods,
&_is_declared_atomic,
CHECK);
@@ -6927,20 +6986,26 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st
return;
}

// For an inline class, only java/lang/Object or special abstract classes
// are acceptable super classes.
if (_access_flags.get_flags() & JVM_ACC_VALUE) {
if (_super_klass->name() != vmSymbols::java_lang_Object()) {
guarantee_property(_super_klass->is_abstract(),
"Inline type must have java.lang.Object or an abstract class as its superclass, class file %s",
CHECK);
}
}

// Make sure super class is not final
if (_super_klass->is_final()) {
THROW_MSG(vmSymbols::java_lang_VerifyError(), "Cannot inherit from final class");
}

// For an inline class, only java/lang/Object or special abstract classes
// are acceptable super classes.
if (is_value_type()) {
const InstanceKlass* super_ik = _super_klass;
if (super_ik->invalid_inline_super()) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_IncompatibleClassChangeError(),
"inline class %s has an invalid super class %s",
_class_name->as_klass_external_name(),
_super_klass->external_name());
return;
}
}
}

if (_class_name == vmSymbols::java_lang_NonTearable() && _loader_data->class_loader() == NULL) {
@@ -7019,7 +7084,6 @@ void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const st

// Compute reference type
_rt = (NULL ==_super_klass) ? REF_NONE : _super_klass->reference_type();

}

void ClassFileParser::set_klass(InstanceKlass* klass) {
@@ -202,6 +202,8 @@ class ClassFileParser {
bool _is_empty_value;
bool _is_naturally_atomic;
bool _is_declared_atomic;
bool _invalid_inline_super; // if true, invalid super type for an inline type.
bool _invalid_identity_super; // if true, invalid super type for an identity type.

// precomputed flags
bool _has_finalizer;
@@ -248,6 +250,7 @@ class ClassFileParser {
void parse_interfaces(const ClassFileStream* const stream,
const int itfs_len,
ConstantPool* const cp,
bool is_inline_type,
bool* has_nonstatic_concrete_methods,
bool* is_declared_atomic,
TRAPS);
@@ -587,6 +590,10 @@ class ClassFileParser {
bool is_value_type() const { return _access_flags.is_value_type(); }
bool is_value_capable_class() const;
bool has_flattenable_fields() const { return _has_flattenable_fields; }
bool invalid_inline_super() const { return _invalid_inline_super; }
void set_invalid_inline_super() { _invalid_inline_super = true; }
bool invalid_identity_super() const { return _invalid_identity_super; }
void set_invalid_identity_super() { _invalid_identity_super = true; }

u2 java_fields_count() const { return _java_fields_count; }

@@ -294,7 +294,9 @@ class InstanceKlass: public Klass {
_misc_has_value_fields = 1 << 19, // has value fields and related embedded section is not empty
_misc_is_empty_value = 1 << 20, // empty value type
_misc_is_naturally_atomic = 1 << 21, // loaded/stored in one instruction
_misc_is_declared_atomic = 1 << 22 // implements jl.NonTearable
_misc_is_declared_atomic = 1 << 22, // implements jl.NonTearable
_misc_invalid_inline_super = 1 << 23, // invalid super type for an inline type
_misc_invalid_identity_super = 1 << 24 // invalid super type for an identity type
};
u2 shared_loader_type_bits() const {
return _misc_is_shared_boot_class|_misc_is_shared_platform_class|_misc_is_shared_app_class;
@@ -462,6 +464,23 @@ class InstanceKlass: public Klass {
_misc_flags |= _misc_is_declared_atomic;
}

// Query if class is an invalid super class for an inline type.
bool invalid_inline_super() const {
return (_misc_flags & _misc_invalid_inline_super) != 0;
}
// Initialized in the class file parser, not changed later.
void set_invalid_inline_super() {
_misc_flags |= _misc_invalid_inline_super;
}
// Query if class is an invalid super class for an identity type.
bool invalid_identity_super() const {
return (_misc_flags & _misc_invalid_identity_super) != 0;
}
// Initialized in the class file parser, not changed later.
void set_invalid_identity_super() {
_misc_flags |= _misc_invalid_identity_super;
}

// field sizes
int nonstatic_field_size() const { return _nonstatic_field_size; }
void set_nonstatic_field_size(int size) { _nonstatic_field_size = size; }
@@ -629,7 +629,7 @@ bool Method::is_vanilla_constructor() const {
// which only calls the superclass vanilla constructor and possibly does stores of
// zero constants to local fields:
//
// aload_0
// aload_0, _fast_aload_0, or _nofast_aload_0
// invokespecial
// indexbyte1
// indexbyte2
@@ -2300,6 +2300,8 @@ typedef HashtableEntry<InstanceKlass*, mtClass> KlassHashtableEntry;
declare_constant(InstanceKlass::_misc_is_shared_boot_class) \
declare_constant(InstanceKlass::_misc_is_shared_platform_class) \
declare_constant(InstanceKlass::_misc_is_shared_app_class) \
declare_constant(InstanceKlass::_misc_invalid_inline_super) \
declare_constant(InstanceKlass::_misc_invalid_identity_super) \
\
/*********************************/ \
/* Symbol* - symbol max length */ \
@@ -60,9 +60,6 @@ public static void main(String[] args) throws Exception {
runTest("ValueMethodSynch",
"Method getInt in class ValueMethodSynch (an inline class) has illegal modifiers");

runTest("ValueSuperClass",
"Inline type must have java.lang.Object or an abstract class as its superclass");

// Test that ClassCircularityError gets detected for instance fields.
System.out.println("Testing ClassCircularityError for instance fields");
try {

0 comments on commit b00578f

Please sign in to comment.