mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
8205611: Improve the wording of LinkageErrors to include module and class loader information
Clean up the wording of loader constraint violations to include the module and class loader information. Reviewed-by: coleenp, goetz, hseigel
This commit is contained in:
parent
e8fcd927c3
commit
cc58241bec
9 changed files with 149 additions and 194 deletions
|
@ -4129,37 +4129,6 @@ oop java_lang_ClassLoader::unnamedModule(oop loader) {
|
||||||
return loader->obj_field(unnamedModule_offset);
|
return loader->obj_field(unnamedModule_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Caller needs ResourceMark.
|
|
||||||
const char* java_lang_ClassLoader::describe_external(const oop loader) {
|
|
||||||
ClassLoaderData *cld = ClassLoaderData::class_loader_data(loader);
|
|
||||||
const char* name = cld->loader_name_and_id();
|
|
||||||
|
|
||||||
// bootstrap loader
|
|
||||||
if (loader == NULL) {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool well_known_loader = SystemDictionary::is_system_class_loader(loader) ||
|
|
||||||
SystemDictionary::is_platform_class_loader(loader);
|
|
||||||
|
|
||||||
stringStream ss;
|
|
||||||
ss.print("%s (instance of %s", name, loader->klass()->external_name());
|
|
||||||
if (!well_known_loader) {
|
|
||||||
oop pl = java_lang_ClassLoader::parent(loader);
|
|
||||||
ClassLoaderData *pl_cld = ClassLoaderData::class_loader_data(pl);
|
|
||||||
const char* parentName = pl_cld->loader_name_and_id();
|
|
||||||
if (pl != NULL) {
|
|
||||||
ss.print(", child of %s %s", parentName, pl->klass()->external_name());
|
|
||||||
} else {
|
|
||||||
// bootstrap loader
|
|
||||||
ss.print(", child of %s", parentName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ss.print(")");
|
|
||||||
|
|
||||||
return ss.as_string();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Support for java_lang_System
|
// Support for java_lang_System
|
||||||
//
|
//
|
||||||
#define SYSTEM_FIELDS_DO(macro) \
|
#define SYSTEM_FIELDS_DO(macro) \
|
||||||
|
|
|
@ -1310,12 +1310,6 @@ class java_lang_ClassLoader : AllStatic {
|
||||||
// Debugging
|
// Debugging
|
||||||
friend class JavaClasses;
|
friend class JavaClasses;
|
||||||
friend class ClassFileParser; // access to number_of_fake_fields
|
friend class ClassFileParser; // access to number_of_fake_fields
|
||||||
|
|
||||||
// Describe ClassLoader for exceptions, tracing ...
|
|
||||||
// Prints "<name>" (instance of <classname>, child of "<name>" <classname>).
|
|
||||||
// If a classloader has no name, it prints <unnamed> instead. The output
|
|
||||||
// for well known loaders (system/platform) is abbreviated.
|
|
||||||
static const char* describe_external(const oop loader);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2084,9 +2084,9 @@ void SystemDictionary::check_constraints(unsigned int d_hash,
|
||||||
assert(check->is_instance_klass(), "noninstance in systemdictionary");
|
assert(check->is_instance_klass(), "noninstance in systemdictionary");
|
||||||
if ((defining == true) || (k != check)) {
|
if ((defining == true) || (k != check)) {
|
||||||
throwException = true;
|
throwException = true;
|
||||||
ss.print("loader %s", java_lang_ClassLoader::describe_external(class_loader()));
|
ss.print("loader %s", loader_data->loader_name_and_id());
|
||||||
ss.print(" attempted duplicate %s definition for %s.",
|
ss.print(" attempted duplicate %s definition for %s. (%s)",
|
||||||
k->external_kind(), k->external_name());
|
k->external_kind(), k->external_name(), k->class_in_module_of_loader(false, true));
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2100,15 +2100,17 @@ void SystemDictionary::check_constraints(unsigned int d_hash,
|
||||||
if (throwException == false) {
|
if (throwException == false) {
|
||||||
if (constraints()->check_or_update(k, class_loader, name) == false) {
|
if (constraints()->check_or_update(k, class_loader, name) == false) {
|
||||||
throwException = true;
|
throwException = true;
|
||||||
ss.print("loader constraint violation: loader %s",
|
ss.print("loader constraint violation: loader %s", loader_data->loader_name_and_id());
|
||||||
java_lang_ClassLoader::describe_external(class_loader()));
|
|
||||||
ss.print(" wants to load %s %s.",
|
ss.print(" wants to load %s %s.",
|
||||||
k->external_kind(), k->external_name());
|
k->external_kind(), k->external_name());
|
||||||
Klass *existing_klass = constraints()->find_constrained_klass(name, class_loader);
|
Klass *existing_klass = constraints()->find_constrained_klass(name, class_loader);
|
||||||
if (existing_klass->class_loader() != class_loader()) {
|
if (existing_klass->class_loader() != class_loader()) {
|
||||||
ss.print(" A different %s with the same name was previously loaded by %s.",
|
ss.print(" A different %s with the same name was previously loaded by %s. (%s)",
|
||||||
existing_klass->external_kind(),
|
existing_klass->external_kind(),
|
||||||
java_lang_ClassLoader::describe_external(existing_klass->class_loader()));
|
existing_klass->class_loader_data()->loader_name_and_id(),
|
||||||
|
existing_klass->class_in_module_of_loader(false, true));
|
||||||
|
} else {
|
||||||
|
ss.print(" (%s)", k->class_in_module_of_loader(false, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -669,23 +669,28 @@ void LinkResolver::check_method_loader_constraints(const LinkInfo& link_info,
|
||||||
SystemDictionary::check_signature_loaders(link_info.signature(), current_loader,
|
SystemDictionary::check_signature_loaders(link_info.signature(), current_loader,
|
||||||
resolved_loader, true, CHECK);
|
resolved_loader, true, CHECK);
|
||||||
if (failed_type_symbol != NULL) {
|
if (failed_type_symbol != NULL) {
|
||||||
const char* msg = "loader constraint violation: when resolving %s"
|
Klass* current_class = link_info.current_klass();
|
||||||
" \"%s\" the class loader %s of the current class, %s,"
|
ClassLoaderData* current_loader_data = current_class->class_loader_data();
|
||||||
" and the class loader %s for the method's defining class, %s, have"
|
assert(current_loader_data != NULL, "current class has no class loader data");
|
||||||
" different Class objects for the type %s used in the signature";
|
Klass* resolved_method_class = resolved_method->method_holder();
|
||||||
char* sig = link_info.method_string();
|
ClassLoaderData* target_loader_data = resolved_method_class->class_loader_data();
|
||||||
const char* loader1_name = java_lang_ClassLoader::describe_external(current_loader());
|
assert(target_loader_data != NULL, "resolved method's class has no class loader data");
|
||||||
char* current = link_info.current_klass()->name()->as_C_string();
|
|
||||||
const char* loader2_name = java_lang_ClassLoader::describe_external(resolved_loader());
|
stringStream ss;
|
||||||
char* target = resolved_method->method_holder()->name()->as_C_string();
|
ss.print("loader constraint violation: when resolving %s"
|
||||||
char* failed_type_name = failed_type_symbol->as_C_string();
|
" \"%s\" the class loader %s of the current class, %s,"
|
||||||
size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1_name) +
|
" and the class loader %s for the method's defining class, %s, have"
|
||||||
strlen(current) + strlen(loader2_name) + strlen(target) +
|
" different Class objects for the type %s used in the signature (%s; %s)",
|
||||||
strlen(failed_type_name) + strlen(method_type) + 1;
|
method_type,
|
||||||
char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen);
|
link_info.method_string(),
|
||||||
jio_snprintf(buf, buflen, msg, method_type, sig, loader1_name, current, loader2_name,
|
current_loader_data->loader_name_and_id(),
|
||||||
target, failed_type_name);
|
current_class->name()->as_C_string(),
|
||||||
THROW_MSG(vmSymbols::java_lang_LinkageError(), buf);
|
target_loader_data->loader_name_and_id(),
|
||||||
|
resolved_method_class->name()->as_C_string(),
|
||||||
|
failed_type_symbol->as_C_string(),
|
||||||
|
current_class->class_in_module_of_loader(false, true),
|
||||||
|
resolved_method_class->class_in_module_of_loader(false, true));
|
||||||
|
THROW_MSG(vmSymbols::java_lang_LinkageError(), ss.as_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -702,23 +707,23 @@ void LinkResolver::check_field_loader_constraints(Symbol* field, Symbol* sig,
|
||||||
false,
|
false,
|
||||||
CHECK);
|
CHECK);
|
||||||
if (failed_type_symbol != NULL) {
|
if (failed_type_symbol != NULL) {
|
||||||
const char* msg = "loader constraint violation: when resolving field"
|
stringStream ss;
|
||||||
" \"%s\" of type %s, the class loader %s of the current class, "
|
|
||||||
"%s, and the class loader %s for the field's defining "
|
|
||||||
"type, %s, have different Class objects for type %s";
|
|
||||||
const char* field_name = field->as_C_string();
|
|
||||||
const char* loader1_name = java_lang_ClassLoader::describe_external(ref_loader());
|
|
||||||
const char* sel = sel_klass->external_name();
|
|
||||||
const char* loader2_name = java_lang_ClassLoader::describe_external(sel_loader());
|
|
||||||
const char* failed_type_name = failed_type_symbol->as_klass_external_name();
|
const char* failed_type_name = failed_type_symbol->as_klass_external_name();
|
||||||
const char* curr_klass_name = current_klass->external_name();
|
|
||||||
size_t buflen = strlen(msg) + strlen(field_name) + 2 * strlen(failed_type_name) +
|
ss.print("loader constraint violation: when resolving field"
|
||||||
strlen(loader1_name) + strlen(curr_klass_name) +
|
" \"%s\" of type %s, the class loader %s of the current class, "
|
||||||
strlen(loader2_name) + strlen(sel) + 1;
|
"%s, and the class loader %s for the field's defining "
|
||||||
char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen);
|
"type, %s, have different Class objects for type %s (%s; %s)",
|
||||||
jio_snprintf(buf, buflen, msg, field_name, failed_type_name, loader1_name,
|
field->as_C_string(),
|
||||||
curr_klass_name, loader2_name, sel, failed_type_name);
|
failed_type_name,
|
||||||
THROW_MSG(vmSymbols::java_lang_LinkageError(), buf);
|
current_klass->class_loader_data()->loader_name_and_id(),
|
||||||
|
current_klass->external_name(),
|
||||||
|
sel_klass->class_loader_data()->loader_name_and_id(),
|
||||||
|
sel_klass->external_name(),
|
||||||
|
failed_type_name,
|
||||||
|
current_klass->class_in_module_of_loader(false, true),
|
||||||
|
sel_klass->class_in_module_of_loader(false, true));
|
||||||
|
THROW_MSG(vmSymbols::java_lang_LinkageError(), ss.as_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -506,24 +506,21 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, const methodHand
|
||||||
super_loader, true,
|
super_loader, true,
|
||||||
CHECK_(false));
|
CHECK_(false));
|
||||||
if (failed_type_symbol != NULL) {
|
if (failed_type_symbol != NULL) {
|
||||||
const char* msg = "loader constraint violation for class %s: when selecting "
|
stringStream ss;
|
||||||
"overriding method %s the class loader %s of the "
|
ss.print("loader constraint violation for class %s: when selecting "
|
||||||
"selected method's type %s, and the class loader %s for its super "
|
"overriding method %s the class loader %s of the "
|
||||||
"type %s have different Class objects for the type %s used in the signature";
|
"selected method's type %s, and the class loader %s for its super "
|
||||||
const char* curr_class = klass->external_name();
|
"type %s have different Class objects for the type %s used in the signature (%s; %s)",
|
||||||
const char* method = target_method()->name_and_sig_as_C_string();
|
klass->external_name(),
|
||||||
const char* loader1 = java_lang_ClassLoader::describe_external(target_loader());
|
target_method()->name_and_sig_as_C_string(),
|
||||||
const char* sel_class = target_klass->external_name();
|
target_klass->class_loader_data()->loader_name_and_id(),
|
||||||
const char* loader2 = java_lang_ClassLoader::describe_external(super_loader());
|
target_klass->external_name(),
|
||||||
const char* super_class = super_klass->external_name();
|
super_klass->class_loader_data()->loader_name_and_id(),
|
||||||
const char* failed_type_name = failed_type_symbol->as_klass_external_name();
|
super_klass->external_name(),
|
||||||
size_t buflen = strlen(msg) + strlen(curr_class) + strlen(method) +
|
failed_type_symbol->as_klass_external_name(),
|
||||||
strlen(loader1) + strlen(sel_class) + strlen(loader2) +
|
target_klass->class_in_module_of_loader(false, true),
|
||||||
strlen(super_class) + strlen(failed_type_name);
|
super_klass->class_in_module_of_loader(false, true));
|
||||||
char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen);
|
THROW_MSG_(vmSymbols::java_lang_LinkageError(), ss.as_string(), false);
|
||||||
jio_snprintf(buf, buflen, msg, curr_class, method, loader1, sel_class, loader2,
|
|
||||||
super_class, failed_type_name);
|
|
||||||
THROW_MSG_(vmSymbols::java_lang_LinkageError(), buf, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1242,25 +1239,22 @@ void klassItable::initialize_itable_for_interface(int method_table_offset, Klass
|
||||||
interface_loader,
|
interface_loader,
|
||||||
true, CHECK);
|
true, CHECK);
|
||||||
if (failed_type_symbol != NULL) {
|
if (failed_type_symbol != NULL) {
|
||||||
const char* msg = "loader constraint violation in interface itable"
|
stringStream ss;
|
||||||
" initialization for class %s: when selecting method %s the"
|
ss.print("loader constraint violation in interface itable"
|
||||||
" class loader %s for super interface %s, and the class"
|
" initialization for class %s: when selecting method %s the"
|
||||||
" loader %s of the selected method's type, %s have"
|
" class loader %s for super interface %s, and the class"
|
||||||
" different Class objects for the type %s used in the signature";
|
" loader %s of the selected method's type, %s have"
|
||||||
const char* current = _klass->external_name();
|
" different Class objects for the type %s used in the signature (%s; %s)",
|
||||||
const char* sig = m->name_and_sig_as_C_string();
|
_klass->external_name(),
|
||||||
const char* loader1 = java_lang_ClassLoader::describe_external(interface_loader());
|
m->name_and_sig_as_C_string(),
|
||||||
const char* iface = InstanceKlass::cast(interf)->external_name();
|
interf->class_loader_data()->loader_name_and_id(),
|
||||||
const char* loader2 = java_lang_ClassLoader::describe_external(method_holder_loader());
|
interf->external_name(),
|
||||||
const char* mclass = target()->method_holder()->external_name();
|
target()->method_holder()->class_loader_data()->loader_name_and_id(),
|
||||||
const char* failed_type_name = failed_type_symbol->as_klass_external_name();
|
target()->method_holder()->external_name(),
|
||||||
size_t buflen = strlen(msg) + strlen(current) + strlen(sig) +
|
failed_type_symbol->as_klass_external_name(),
|
||||||
strlen(loader1) + strlen(iface) + strlen(loader2) + strlen(mclass) +
|
interf->class_in_module_of_loader(false, true),
|
||||||
strlen(failed_type_name);
|
target()->method_holder()->class_in_module_of_loader(false, true));
|
||||||
char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen);
|
THROW_MSG(vmSymbols::java_lang_LinkageError(), ss.as_string());
|
||||||
jio_snprintf(buf, buflen, msg, current, sig, loader1, iface,
|
|
||||||
loader2, mclass, failed_type_name);
|
|
||||||
THROW_MSG(vmSymbols::java_lang_LinkageError(), buf);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,11 +78,9 @@ public class Test {
|
||||||
// Break the expectedErrorMessage into 2 pieces since the loader name will include
|
// Break the expectedErrorMessage into 2 pieces since the loader name will include
|
||||||
// its identity hash and can not be compared against.
|
// its identity hash and can not be compared against.
|
||||||
static String expectedErrorMessage_part1 = "loader constraint violation: loader PreemptingClassLoader @";
|
static String expectedErrorMessage_part1 = "loader constraint violation: loader PreemptingClassLoader @";
|
||||||
static String expectedErrorMessage_part2 = " (instance of PreemptingClassLoader, " +
|
static String expectedErrorMessage_part2 = " wants to load class test.D_ambgs. A different class " +
|
||||||
"child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) wants to load " +
|
"with the same name was previously loaded by 'app'. " +
|
||||||
"class test.D_ambgs. A different class with the same name was previously loaded " +
|
"(test.D_ambgs is in unnamed module of loader 'app')";
|
||||||
"by 'app' (instance of jdk.internal.loader.ClassLoaders$AppClassLoader).";
|
|
||||||
|
|
||||||
public static void test_access() throws Exception {
|
public static void test_access() throws Exception {
|
||||||
try {
|
try {
|
||||||
// Make a Class 'D_ambgs' under the default loader.
|
// Make a Class 'D_ambgs' under the default loader.
|
||||||
|
@ -118,4 +116,3 @@ public class Test {
|
||||||
test_access();
|
test_access();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,26 +40,21 @@ public class Test {
|
||||||
// Break each expectedErrorMessage into 2 parts due to the class loader name containing
|
// Break each expectedErrorMessage into 2 parts due to the class loader name containing
|
||||||
// the unique @<id> identity hash which cannot be compared against.
|
// the unique @<id> identity hash which cannot be compared against.
|
||||||
static String expectedErrorMessage1_part1 = "loader PreemptingClassLoader @";
|
static String expectedErrorMessage1_part1 = "loader PreemptingClassLoader @";
|
||||||
static String expectedErrorMessage1_part2 =
|
static String expectedErrorMessage1_part2 = " attempted duplicate class definition for test.Foo. (test.Foo is in unnamed module of loader PreemptingClassLoader @";
|
||||||
" (instance of PreemptingClassLoader, " +
|
static String expectedErrorMessage1_part3 = ", parent loader 'app')";
|
||||||
"child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
|
||||||
"attempted duplicate class definition for test.Foo.";
|
|
||||||
|
|
||||||
// Check that all names have external formatting ('.' and not '/' in package names).
|
// Check that all names have external formatting ('.' and not '/' in package names).
|
||||||
// Check for name and parent of class loader.
|
// Check for name and parent of class loader.
|
||||||
static String expectedErrorMessage2_part1 = "loader 'DuplicateLE_Test_Loader' @";
|
static String expectedErrorMessage2_part1 = "loader 'DuplicateLE_Test_Loader' @";
|
||||||
static String expectedErrorMessage2_part2 =
|
static String expectedErrorMessage2_part2 = " attempted duplicate class definition for test.Foo. (test.Foo is in unnamed module of loader 'DuplicateLE_Test_Loader' @";
|
||||||
" (instance of PreemptingClassLoader, " +
|
static String expectedErrorMessage2_part3 = ", parent loader 'app')";
|
||||||
"child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
|
||||||
"attempted duplicate class definition for test.Foo.";
|
|
||||||
|
|
||||||
// Check that all names have external formatting ('.' and not '/' in package names).
|
// Check that all names have external formatting ('.' and not '/' in package names).
|
||||||
// Check for name and parent of class loader. Type should be mentioned as 'interface'.
|
// Check for name and parent of class loader. Type should be mentioned as 'interface'.
|
||||||
static String expectedErrorMessage3_part1 = "loader 'DuplicateLE_Test_Loader_IF' @";
|
static String expectedErrorMessage3_part1 = "loader 'DuplicateLE_Test_Loader_IF' @";
|
||||||
static String expectedErrorMessage3_part2 =
|
static String expectedErrorMessage3_part2 = " attempted duplicate interface definition for test.J. (test.J is in unnamed module of loader 'DuplicateLE_Test_Loader_IF' @";
|
||||||
" (instance of PreemptingClassLoader, " +
|
static String expectedErrorMessage3_part3 = ", parent loader 'app')";
|
||||||
"child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
|
||||||
"attempted duplicate interface definition for test.J.";
|
|
||||||
|
|
||||||
// Test that the error message is correct when a loader constraint error is
|
// Test that the error message is correct when a loader constraint error is
|
||||||
// detected during vtable creation.
|
// detected during vtable creation.
|
||||||
|
@ -68,8 +63,11 @@ public class Test {
|
||||||
// overrides "J.m()LFoo;". But, Task's class Foo and super type J's class Foo
|
// overrides "J.m()LFoo;". But, Task's class Foo and super type J's class Foo
|
||||||
// are different. So, a LinkageError exception should be thrown because the
|
// are different. So, a LinkageError exception should be thrown because the
|
||||||
// loader constraint check will fail.
|
// loader constraint check will fail.
|
||||||
public static void test(String loaderName, String expectedErrorMessage_part1,
|
public static void test(String loaderName,
|
||||||
String expectedErrorMessage_part2, String testType) throws Exception {
|
String expectedErrorMessage_part1,
|
||||||
|
String expectedErrorMessage_part2,
|
||||||
|
String expectedErrorMessage_part3,
|
||||||
|
String testType) throws Exception {
|
||||||
String[] classNames = {testType};
|
String[] classNames = {testType};
|
||||||
ClassLoader l = new PreemptingClassLoader(loaderName, classNames, false);
|
ClassLoader l = new PreemptingClassLoader(loaderName, classNames, false);
|
||||||
l.loadClass(testType);
|
l.loadClass(testType);
|
||||||
|
@ -79,7 +77,8 @@ public class Test {
|
||||||
} catch (LinkageError e) {
|
} catch (LinkageError e) {
|
||||||
String errorMsg = e.getMessage();
|
String errorMsg = e.getMessage();
|
||||||
if (!errorMsg.contains(expectedErrorMessage_part1) ||
|
if (!errorMsg.contains(expectedErrorMessage_part1) ||
|
||||||
!errorMsg.contains(expectedErrorMessage_part2)) {
|
!errorMsg.contains(expectedErrorMessage_part2) ||
|
||||||
|
!errorMsg.contains(expectedErrorMessage_part3)) {
|
||||||
System.out.println("Expected: " + expectedErrorMessage_part1 + "<id>" + expectedErrorMessage_part2 + "\n" +
|
System.out.println("Expected: " + expectedErrorMessage_part1 + "<id>" + expectedErrorMessage_part2 + "\n" +
|
||||||
"but got: " + errorMsg);
|
"but got: " + errorMsg);
|
||||||
throw new RuntimeException("Wrong LinkageError exception thrown: " + errorMsg);
|
throw new RuntimeException("Wrong LinkageError exception thrown: " + errorMsg);
|
||||||
|
@ -89,9 +88,11 @@ public class Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String args[]) throws Exception {
|
public static void main(String args[]) throws Exception {
|
||||||
test(null, expectedErrorMessage1_part1, expectedErrorMessage1_part2, "test.Foo");
|
test(null, expectedErrorMessage1_part1, expectedErrorMessage1_part2,
|
||||||
test("DuplicateLE_Test_Loader", expectedErrorMessage2_part1, expectedErrorMessage2_part2, "test.Foo");
|
expectedErrorMessage1_part3, "test.Foo");
|
||||||
test("DuplicateLE_Test_Loader_IF", expectedErrorMessage3_part1, expectedErrorMessage3_part2, "test.J");
|
test("DuplicateLE_Test_Loader", expectedErrorMessage2_part1, expectedErrorMessage2_part2,
|
||||||
|
expectedErrorMessage2_part3, "test.Foo");
|
||||||
|
test("DuplicateLE_Test_Loader_IF", expectedErrorMessage3_part1, expectedErrorMessage3_part2,
|
||||||
|
expectedErrorMessage3_part3, "test.J");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,31 +35,25 @@
|
||||||
|
|
||||||
public class Test {
|
public class Test {
|
||||||
|
|
||||||
// Break expected error messages into 2 parts since the loader name includes its identity
|
// Break expected error messages into 3 parts since the loader name includes its identity
|
||||||
// hash which is unique and can't be compared against.
|
// hash which is unique and can't be compared against.
|
||||||
static String expectedErrorMessage1_part1 =
|
static String expectedErrorMessage1_part1 = "loader constraint violation in interface itable initialization for " +
|
||||||
"loader constraint violation in interface itable initialization for class test.C: " +
|
"class test.C: when selecting method test.I.m()Ltest/Foo; the class loader " +
|
||||||
"when selecting method test.I.m()Ltest/Foo; " +
|
"PreemptingClassLoader @";
|
||||||
"the class loader PreemptingClassLoader @";
|
static String expectedErrorMessage1_part2 = " for super interface test.I, and the class loader 'app' of the " +
|
||||||
static String expectedErrorMessage1_part2 =
|
"selected method's type, test.J have different Class objects for the " +
|
||||||
" (instance of PreemptingClassLoader, " +
|
"type test.Foo used in the signature (test.I is in unnamed module of loader " +
|
||||||
"child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
"PreemptingClassLoader @";
|
||||||
"for super interface test.I, and the class loader 'app' " +
|
static String expectedErrorMessage1_part3 = ", parent loader 'app'; test.J is in unnamed module of loader 'app')";
|
||||||
"(instance of jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
|
||||||
"of the selected method's type, test.J have different Class objects " +
|
|
||||||
"for the type test.Foo used in the signature";
|
|
||||||
|
|
||||||
static String expectedErrorMessage2_part1 =
|
static String expectedErrorMessage2_part1 = "loader constraint violation in interface itable initialization for " +
|
||||||
"loader constraint violation in interface itable initialization for class test.C: " +
|
"class test.C: when selecting method test.I.m()Ltest/Foo; the class loader " +
|
||||||
"when selecting method test.I.m()Ltest/Foo; " +
|
"'ItableLdrCnstrnt_Test_Loader' @";
|
||||||
"the class loader 'ItableLdrCnstrnt_Test_Loader' @";
|
static String expectedErrorMessage2_part2 = " for super interface test.I, and the class loader 'app' of the " +
|
||||||
static String expectedErrorMessage2_part2 =
|
"selected method's type, test.J have different Class objects for the " +
|
||||||
" (instance of PreemptingClassLoader, " +
|
"type test.Foo used in the signature (test.I is in unnamed module of loader " +
|
||||||
"child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
"'ItableLdrCnstrnt_Test_Loader' @";
|
||||||
"for super interface test.I, and the class loader 'app' " +
|
static String expectedErrorMessage2_part3 = ", parent loader 'app'; test.J is in unnamed module of loader 'app')";
|
||||||
"(instance of jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
|
||||||
"of the selected method's type, test.J have different Class objects " +
|
|
||||||
"for the type test.Foo used in the signature";
|
|
||||||
|
|
||||||
// Test that the error message is correct when a loader constraint error is
|
// Test that the error message is correct when a loader constraint error is
|
||||||
// detected during itable creation.
|
// detected during itable creation.
|
||||||
|
@ -71,7 +65,8 @@ public class Test {
|
||||||
// exception should be thrown because the loader constraint check will fail.
|
// exception should be thrown because the loader constraint check will fail.
|
||||||
public static void test(String loaderName,
|
public static void test(String loaderName,
|
||||||
String expectedErrorMessage_part1,
|
String expectedErrorMessage_part1,
|
||||||
String expectedErrorMessage_part2) throws Exception {
|
String expectedErrorMessage_part2,
|
||||||
|
String expectedErrorMessage_part3) throws Exception {
|
||||||
Class<?> c = test.Foo.class; // Forces standard class loader to load Foo.
|
Class<?> c = test.Foo.class; // Forces standard class loader to load Foo.
|
||||||
String[] classNames = {"test.Task", "test.Foo", "test.C", "test.I"};
|
String[] classNames = {"test.Task", "test.Foo", "test.C", "test.I"};
|
||||||
ClassLoader l = new PreemptingClassLoader(loaderName, classNames);
|
ClassLoader l = new PreemptingClassLoader(loaderName, classNames);
|
||||||
|
@ -82,7 +77,8 @@ public class Test {
|
||||||
} catch (LinkageError e) {
|
} catch (LinkageError e) {
|
||||||
String errorMsg = e.getMessage();
|
String errorMsg = e.getMessage();
|
||||||
if (!errorMsg.contains(expectedErrorMessage_part1) ||
|
if (!errorMsg.contains(expectedErrorMessage_part1) ||
|
||||||
!errorMsg.contains(expectedErrorMessage_part2)) {
|
!errorMsg.contains(expectedErrorMessage_part2) ||
|
||||||
|
!errorMsg.contains(expectedErrorMessage_part3)) {
|
||||||
System.out.println("Expected: " + expectedErrorMessage_part1 + "<id>" + expectedErrorMessage_part2 + "\n" +
|
System.out.println("Expected: " + expectedErrorMessage_part1 + "<id>" + expectedErrorMessage_part2 + "\n" +
|
||||||
"but got: " + errorMsg);
|
"but got: " + errorMsg);
|
||||||
throw new RuntimeException("Wrong LinkageError exception thrown: " + errorMsg);
|
throw new RuntimeException("Wrong LinkageError exception thrown: " + errorMsg);
|
||||||
|
@ -92,7 +88,7 @@ public class Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String... args) throws Exception {
|
public static void main(String... args) throws Exception {
|
||||||
test(null, expectedErrorMessage1_part1, expectedErrorMessage1_part2);
|
test(null, expectedErrorMessage1_part1, expectedErrorMessage1_part2, expectedErrorMessage1_part3);
|
||||||
test("ItableLdrCnstrnt_Test_Loader", expectedErrorMessage2_part1, expectedErrorMessage2_part2);
|
test("ItableLdrCnstrnt_Test_Loader", expectedErrorMessage2_part1, expectedErrorMessage2_part2, expectedErrorMessage2_part3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,31 +35,25 @@
|
||||||
|
|
||||||
public class Test {
|
public class Test {
|
||||||
|
|
||||||
// Break expected error messages into 2 parts since the loader name includes its identity
|
// Break expected error messages into 3 parts since the loader name includes its identity
|
||||||
// hash which is unique and can't be compared against.
|
// hash which is unique and can't be compared against.
|
||||||
static String expectedErrorMessage1_part1 =
|
static String expectedErrorMessage1_part1 = "loader constraint violation for class test.Task: when " +
|
||||||
"loader constraint violation for class test.Task: " +
|
"selecting overriding method test.Task.m()Ltest/Foo; the " +
|
||||||
"when selecting overriding method test.Task.m()Ltest/Foo; " +
|
"class loader PreemptingClassLoader @";
|
||||||
"the class loader PreemptingClassLoader @";
|
static String expectedErrorMessage1_part2 = " of the selected method's type test.Task, and the class " +
|
||||||
static String expectedErrorMessage1_part2 =
|
"loader 'app' for its super type test.J have different Class objects " +
|
||||||
" (instance of PreemptingClassLoader, " +
|
"for the type test.Foo used in the signature (test.Task is in unnamed " +
|
||||||
"child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
"module of loader PreemptingClassLoader @";
|
||||||
"of the selected method's type test.Task, " +
|
static String expectedErrorMessage1_part3 = ", parent loader 'app'; test.J is in unnamed module of loader 'app')";
|
||||||
"and the class loader 'app' (instance of jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
|
||||||
"for its super type test.J " +
|
|
||||||
"have different Class objects for the type test.Foo used in the signature";
|
|
||||||
|
|
||||||
static String expectedErrorMessage2_part1 =
|
static String expectedErrorMessage2_part1 = "loader constraint violation for class test.Task: when " +
|
||||||
"loader constraint violation for class test.Task: " +
|
"selecting overriding method test.Task.m()Ltest/Foo; the " +
|
||||||
"when selecting overriding method test.Task.m()Ltest/Foo; " +
|
"class loader 'VtableLdrCnstrnt_Test_Loader' @";
|
||||||
"the class loader 'VtableLdrCnstrnt_Test_Loader' @";
|
static String expectedErrorMessage2_part2 = " of the selected method's type test.Task, and the class " +
|
||||||
static String expectedErrorMessage2_part2 =
|
"loader 'app' for its super type test.J have different Class objects " +
|
||||||
" (instance of PreemptingClassLoader, " +
|
"for the type test.Foo used in the signature (test.Task is in unnamed " +
|
||||||
"child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
"module of loader 'VtableLdrCnstrnt_Test_Loader' @";
|
||||||
"of the selected method's type test.Task, " +
|
static String expectedErrorMessage2_part3 = ", parent loader 'app'; test.J is in unnamed module of loader 'app')";
|
||||||
"and the class loader 'app' (instance of jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
|
||||||
"for its super type test.J " +
|
|
||||||
"have different Class objects for the type test.Foo used in the signature";
|
|
||||||
|
|
||||||
// Test that the error message is correct when a loader constraint error is
|
// Test that the error message is correct when a loader constraint error is
|
||||||
// detected during vtable creation.
|
// detected during vtable creation.
|
||||||
|
@ -70,7 +64,8 @@ public class Test {
|
||||||
// loader constraint check will fail.
|
// loader constraint check will fail.
|
||||||
public static void test(String loaderName,
|
public static void test(String loaderName,
|
||||||
String expectedErrorMessage_part1,
|
String expectedErrorMessage_part1,
|
||||||
String expectedErrorMessage_part2) throws Exception {
|
String expectedErrorMessage_part2,
|
||||||
|
String expectedErrorMessage_part3) throws Exception {
|
||||||
Class<?> c = test.Foo.class; // Forces standard class loader to load Foo.
|
Class<?> c = test.Foo.class; // Forces standard class loader to load Foo.
|
||||||
String[] classNames = {"test.Task", "test.Foo", "test.I"};
|
String[] classNames = {"test.Task", "test.Foo", "test.I"};
|
||||||
ClassLoader l = new PreemptingClassLoader(loaderName, classNames);
|
ClassLoader l = new PreemptingClassLoader(loaderName, classNames);
|
||||||
|
@ -81,7 +76,8 @@ public class Test {
|
||||||
} catch (LinkageError e) {
|
} catch (LinkageError e) {
|
||||||
String errorMsg = e.getMessage();
|
String errorMsg = e.getMessage();
|
||||||
if (!errorMsg.contains(expectedErrorMessage_part1) ||
|
if (!errorMsg.contains(expectedErrorMessage_part1) ||
|
||||||
!errorMsg.contains(expectedErrorMessage_part2)) {
|
!errorMsg.contains(expectedErrorMessage_part2) ||
|
||||||
|
!errorMsg.contains(expectedErrorMessage_part3)) {
|
||||||
System.out.println("Expected: " + expectedErrorMessage_part1 + "<id>" + expectedErrorMessage_part2 + "\n" +
|
System.out.println("Expected: " + expectedErrorMessage_part1 + "<id>" + expectedErrorMessage_part2 + "\n" +
|
||||||
"but got: " + errorMsg);
|
"but got: " + errorMsg);
|
||||||
throw new RuntimeException("Wrong LinkageError exception thrown: " + errorMsg);
|
throw new RuntimeException("Wrong LinkageError exception thrown: " + errorMsg);
|
||||||
|
@ -91,8 +87,9 @@ public class Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String args[]) throws Exception {
|
public static void main(String args[]) throws Exception {
|
||||||
test(null, expectedErrorMessage1_part1, expectedErrorMessage1_part2);
|
test(null, expectedErrorMessage1_part1,
|
||||||
test("VtableLdrCnstrnt_Test_Loader", expectedErrorMessage2_part1, expectedErrorMessage2_part2);
|
expectedErrorMessage1_part2, expectedErrorMessage1_part3);
|
||||||
|
test("VtableLdrCnstrnt_Test_Loader", expectedErrorMessage2_part1,
|
||||||
|
expectedErrorMessage2_part2, expectedErrorMessage2_part3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue