8243287: Removal of Unsafe::defineAnonymousClass

Reviewed-by: iklam, mchung, alanb, dholmes
This commit is contained in:
Harold Seigel 2021-05-13 12:46:54 +00:00
parent a564f2cbd5
commit e14b026841
122 changed files with 328 additions and 3679 deletions

View file

@ -322,18 +322,6 @@ void ClassFileParser::parse_constant_pool_entries(const ClassFileStream* const s
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 = (u2) strlen(str);
}
unsigned int hash;
Symbol* const result = SymbolTable::lookup_only((const char*)utf8_buffer,
utf8_length,
@ -616,37 +604,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
} // switch(tag)
} // end of for
_first_patched_klass_resolved_index = num_klasses;
cp->allocate_resolved_klasses(_loader_data, num_klasses + _max_num_patched_klasses, CHECK);
if (_cp_patches != NULL) {
// need to treat this_class specially...
// Add dummy utf8 entries in the space reserved for names of patched classes. We'll use "*"
// for now. These will be replaced with actual names of the patched classes in patch_class().
Symbol* s = vmSymbols::star_name();
for (int n=_orig_cp_size; n<cp->length(); n++) {
cp->symbol_at_put(n, s);
}
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);
}
}
}
cp->allocate_resolved_klasses(_loader_data, num_klasses, CHECK);
if (!_need_verify) {
return;
@ -659,7 +617,7 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
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
// check the name
verify_legal_class_name(class_name, CHECK);
break;
}
@ -799,88 +757,6 @@ void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
} // end of for
}
Handle ClassFileParser::clear_cp_patch_at(int index) {
Handle patch = cp_patch_at(index);
_cp_patches->at_put(index, Handle());
assert(!has_cp_patch_at(index), "");
return patch;
}
void ClassFileParser::patch_class(ConstantPool* cp, int class_index, Klass* k, Symbol* name) {
int name_index = _orig_cp_size + _num_patched_klasses;
int resolved_klass_index = _first_patched_klass_resolved_index + _num_patched_klasses;
cp->klass_at_put(class_index, name_index, resolved_klass_index, k, name);
_num_patched_klasses ++;
}
void ClassFileParser::patch_constant_pool(ConstantPool* cp,
int index,
Handle patch,
TRAPS) {
assert(cp != NULL, "invariant");
BasicType patch_type = T_VOID;
switch (cp->tag_at(index).value()) {
case JVM_CONSTANT_UnresolvedClass: {
// Patching a class means pre-resolving it.
// The name in the constant pool is ignored.
if (java_lang_Class::is_instance(patch())) {
guarantee_property(!java_lang_Class::is_primitive(patch()),
"Illegal class patch at %d in class file %s",
index, CHECK);
Klass* k = java_lang_Class::as_Klass(patch());
patch_class(cp, index, k, k->name());
} else {
guarantee_property(java_lang_String::is_instance(patch()),
"Illegal class patch at %d in class file %s",
index, CHECK);
Symbol* const name = java_lang_String::as_symbol(patch());
patch_class(cp, index, NULL, name);
}
break;
}
case JVM_CONSTANT_String: {
// skip this patch and don't clear it. Needs the oop array for resolved
// references to be created first.
return;
}
case JVM_CONSTANT_Integer: patch_type = T_INT; goto patch_prim;
case JVM_CONSTANT_Float: patch_type = T_FLOAT; goto patch_prim;
case JVM_CONSTANT_Long: patch_type = T_LONG; goto patch_prim;
case JVM_CONSTANT_Double: patch_type = T_DOUBLE; goto patch_prim;
patch_prim:
{
jvalue value;
BasicType value_type = java_lang_boxing_object::get_value(patch(), &value);
guarantee_property(value_type == patch_type,
"Illegal primitive patch at %d in class file %s",
index, CHECK);
switch (value_type) {
case T_INT: cp->int_at_put(index, value.i); break;
case T_FLOAT: cp->float_at_put(index, value.f); break;
case T_LONG: cp->long_at_put(index, value.j); break;
case T_DOUBLE: cp->double_at_put(index, value.d); break;
default: assert(false, "");
}
} // end patch_prim label
break;
default: {
// %%% TODO: put method handles into CONSTANT_InterfaceMethodref, etc.
guarantee_property(!has_cp_patch_at(index),
"Illegal unexpected patch at %d in class file %s",
index, CHECK);
return;
}
} // end of switch(tag)
// On fall-through, mark the patch as used.
clear_cp_patch_at(index);
}
class NameSigHash: public ResourceObj {
public:
const Symbol* _name; // name
@ -5429,11 +5305,11 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
ik->set_this_class_index(_this_class_index);
if (_is_hidden || is_unsafe_anonymous()) {
if (_is_hidden) {
// _this_class_index is a CONSTANT_Class entry that refers to this
// hidden or anonymous class itself. If this class needs to refer to its own
// methods or fields, it would use a CONSTANT_MethodRef, etc, which would reference
// _this_class_index. However, because this class is hidden or anonymous (it's
// hidden class itself. If this class needs to refer to its own methods
// or fields, it would use a CONSTANT_MethodRef, etc, which would reference
// _this_class_index. However, because this class is hidden (it's
// not stored in SystemDictionary), _this_class_index cannot be resolved
// with ConstantPool::klass_at_impl, which does a SystemDictionary lookup.
// Therefore, we must eagerly resolve _this_class_index now.
@ -5445,10 +5321,6 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik,
ik->set_has_nonstatic_concrete_methods(_has_nonstatic_concrete_methods);
ik->set_declares_nonstatic_concrete_methods(_declares_nonstatic_concrete_methods);
if (_unsafe_anonymous_host != NULL) {
assert (ik->is_unsafe_anonymous(), "should be the same");
ik->set_unsafe_anonymous_host(_unsafe_anonymous_host);
}
if (_is_hidden) {
ik->set_is_hidden();
}
@ -5614,57 +5486,6 @@ void ClassFileParser::update_class_name(Symbol* new_class_name) {
_class_name->increment_refcount();
}
// For an unsafe anonymous class that is in the unnamed package, move it to its host class's
// package by prepending its host class's package name to its class name and setting
// its _class_name field.
void ClassFileParser::prepend_host_package_name(Thread* current, const InstanceKlass* unsafe_anonymous_host) {
ResourceMark rm(current);
assert(strrchr(_class_name->as_C_string(), JVM_SIGNATURE_SLASH) == NULL,
"Unsafe anonymous class should not be in a package");
TempNewSymbol host_pkg_name =
ClassLoader::package_from_class_name(unsafe_anonymous_host->name());
if (host_pkg_name != NULL) {
int host_pkg_len = host_pkg_name->utf8_length();
int class_name_len = _class_name->utf8_length();
int symbol_len = host_pkg_len + 1 + class_name_len;
char* new_anon_name = NEW_RESOURCE_ARRAY(char, symbol_len + 1);
int n = os::snprintf(new_anon_name, symbol_len + 1, "%.*s/%.*s",
host_pkg_len, host_pkg_name->base(), class_name_len, _class_name->base());
assert(n == symbol_len, "Unexpected number of characters in string");
// Decrement old _class_name to avoid leaking.
_class_name->decrement_refcount();
// Create a symbol and update the anonymous class name.
// The new class name is created with a refcount of one. When installed into the InstanceKlass,
// it'll be two and when the ClassFileParser destructor runs, it'll go back to one and get deleted
// when the class is unloaded.
_class_name = SymbolTable::new_symbol(new_anon_name, symbol_len);
}
}
// If the host class and the anonymous class are in the same package then do
// nothing. If the anonymous class is in the unnamed package then move it to its
// host's package. If the classes are in different packages then throw an IAE
// exception.
void ClassFileParser::fix_unsafe_anonymous_class_name(TRAPS) {
assert(_unsafe_anonymous_host != NULL, "Expected an unsafe anonymous class");
const jbyte* anon_last_slash = UTF8::strrchr((const jbyte*)_class_name->base(),
_class_name->utf8_length(), JVM_SIGNATURE_SLASH);
if (anon_last_slash == NULL) { // Unnamed package
prepend_host_package_name(THREAD, _unsafe_anonymous_host);
} else {
if (!_unsafe_anonymous_host->is_same_class_package(_unsafe_anonymous_host->class_loader(), _class_name)) {
ResourceMark rm(THREAD);
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
err_msg("Host class %s and anonymous class %s are in different packages",
_unsafe_anonymous_host->name()->as_C_string(), _class_name->as_C_string()));
}
}
}
static bool relax_format_check_for(ClassLoaderData* loader_data) {
bool trusted = loader_data->is_boot_class_loader_data() ||
loader_data->is_platform_class_loader_data();
@ -5685,14 +5506,9 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
_stream(stream),
_class_name(NULL),
_loader_data(loader_data),
_unsafe_anonymous_host(cl_info->unsafe_anonymous_host()),
_cp_patches(cl_info->cp_patches()),
_is_hidden(cl_info->is_hidden()),
_can_access_vm_annotations(cl_info->can_access_vm_annotations()),
_num_patched_klasses(0),
_max_num_patched_klasses(0),
_orig_cp_size(0),
_first_patched_klass_resolved_index(0),
_super_klass(),
_cp(NULL),
_fields(NULL),
@ -5769,25 +5585,6 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
_need_verify = Verifier::should_verify_for(_loader_data->class_loader(),
stream->need_verify());
}
if (_cp_patches != NULL) {
int len = _cp_patches->length();
for (int i=0; i<len; i++) {
if (has_cp_patch_at(i)) {
Handle patch = cp_patch_at(i);
if (java_lang_String::is_instance(patch()) || java_lang_Class::is_instance(patch())) {
// We need to append the names of the patched classes to the end of the constant pool,
// because a patched class may have a Utf8 name that's not already included in the
// original constant pool. These class names are used when patch_constant_pool()
// calls patch_class().
//
// Note that a String in cp_patch_at(i) may be used to patch a Utf8, a String, or a Class.
// At this point, we don't know the tag for index i yet, because we haven't parsed the
// constant pool. So we can only assume the worst -- every String is used to patch a Class.
_max_num_patched_klasses++;
}
}
}
}
// synch back verification state to stream
stream->set_verify(_need_verify);
@ -5917,13 +5714,7 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
_orig_cp_size = cp_size;
if (is_hidden()) { // Add a slot for hidden class name.
assert(_max_num_patched_klasses == 0, "Sanity check");
cp_size++;
} else {
if (int(cp_size) + _max_num_patched_klasses > 0xffff) {
THROW_MSG(vmSymbols::java_lang_InternalError(), "not enough space for patched classes");
}
cp_size += _max_num_patched_klasses;
}
_cp = ConstantPool::allocate(_loader_data,
@ -5987,18 +5778,12 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
#ifdef ASSERT
// Basic sanity checks
assert(!(_is_hidden && (_unsafe_anonymous_host != NULL)), "mutually exclusive variants");
if (_unsafe_anonymous_host != NULL) {
assert(_class_name == vmSymbols::unknown_class_name(), "A named anonymous class???");
}
if (_is_hidden) {
assert(_class_name != vmSymbols::unknown_class_name(), "hidden classes should have a special name");
}
#endif
// Update the _class_name as needed depending on whether this is a named,
// un-named, hidden or unsafe-anonymous class.
// Update the _class_name as needed depending on whether this is a named, un-named, or hidden class.
if (_is_hidden) {
assert(_class_name != NULL, "Unexpected null _class_name");
@ -6008,16 +5793,6 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
}
#endif
// NOTE: !_is_hidden does not imply "findable" as it could be an old-style
// "hidden" unsafe-anonymous class
// If this is an anonymous class fix up its name if it is in the unnamed
// package. Otherwise, throw IAE if it is in a different package than
// its host class.
} else if (_unsafe_anonymous_host != NULL) {
update_class_name(class_name_in_cp);
fix_unsafe_anonymous_class_name(CHECK);
} else {
// Check if name in class file matches given name
if (_class_name != class_name_in_cp) {