mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8199852: Print more information about class loaders in LinkageErrors
Reviewed-by: dholmes, lfoltan, gtriantafill
This commit is contained in:
parent
5f40eda733
commit
72a2ac8b8b
28 changed files with 660 additions and 97 deletions
|
@ -4134,6 +4134,48 @@ oop java_lang_ClassLoader::unnamedModule(oop loader) {
|
|||
return loader->obj_field(unnamedModule_offset);
|
||||
}
|
||||
|
||||
// Caller needs ResourceMark.
|
||||
const char* java_lang_ClassLoader::describe_external(const oop loader) {
|
||||
if (loader == NULL) {
|
||||
return "<bootstrap>";
|
||||
}
|
||||
|
||||
bool well_known_loader = SystemDictionary::is_system_class_loader(loader) ||
|
||||
SystemDictionary::is_platform_class_loader(loader);
|
||||
|
||||
const char* name = NULL;
|
||||
oop nameOop = java_lang_ClassLoader::name(loader);
|
||||
if (nameOop != NULL) {
|
||||
name = java_lang_String::as_utf8_string(nameOop);
|
||||
}
|
||||
if (name == NULL) {
|
||||
// Use placeholder for missing name to have fixed message format.
|
||||
name = "<unnamed>";
|
||||
}
|
||||
|
||||
stringStream ss;
|
||||
ss.print("\"%s\" (instance of %s", name, loader->klass()->external_name());
|
||||
if (!well_known_loader) {
|
||||
const char* parentName = NULL;
|
||||
oop pl = java_lang_ClassLoader::parent(loader);
|
||||
if (pl != NULL) {
|
||||
oop parentNameOop = java_lang_ClassLoader::name(pl);
|
||||
if (parentNameOop != NULL) {
|
||||
parentName = java_lang_String::as_utf8_string(parentNameOop);
|
||||
if (parentName == NULL) {
|
||||
parentName = "<unnamed>";
|
||||
}
|
||||
}
|
||||
ss.print(", child of \"%s\" %s", parentName, pl->klass()->external_name());
|
||||
} else {
|
||||
ss.print(", child of <bootstrap>");
|
||||
}
|
||||
}
|
||||
ss.print(")");
|
||||
|
||||
return ss.as_string();
|
||||
}
|
||||
|
||||
// Support for java_lang_System
|
||||
//
|
||||
#define SYSTEM_FIELDS_DO(macro) \
|
||||
|
|
|
@ -1321,6 +1321,12 @@ class java_lang_ClassLoader : AllStatic {
|
|||
// Debugging
|
||||
friend class JavaClasses;
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -2124,10 +2124,19 @@ BasicType SystemDictionary::box_klass_type(Klass* k) {
|
|||
|
||||
void SystemDictionary::check_constraints(unsigned int d_hash,
|
||||
InstanceKlass* k,
|
||||
Handle class_loader, bool defining,
|
||||
Handle class_loader,
|
||||
bool defining,
|
||||
TRAPS) {
|
||||
ResourceMark rm(THREAD);
|
||||
stringStream ss;
|
||||
bool throwException = false;
|
||||
|
||||
const char *linkage_error1 = NULL;
|
||||
const char *linkage_error2 = NULL;
|
||||
const char *linkage_error3 = "";
|
||||
// Remember the loader of the similar class that is already loaded.
|
||||
const char *existing_klass_loader_name = "";
|
||||
|
||||
{
|
||||
Symbol* name = k->name();
|
||||
ClassLoaderData *loader_data = class_loader_data(class_loader);
|
||||
|
@ -2136,16 +2145,18 @@ void SystemDictionary::check_constraints(unsigned int d_hash,
|
|||
|
||||
InstanceKlass* check = find_class(d_hash, name, loader_data->dictionary());
|
||||
if (check != NULL) {
|
||||
// if different InstanceKlass - duplicate class definition,
|
||||
// else - ok, class loaded by a different thread in parallel,
|
||||
// we should only have found it if it was done loading and ok to use
|
||||
// dictionary only holds instance classes, placeholders
|
||||
// also holds array classes
|
||||
// If different InstanceKlass - duplicate class definition,
|
||||
// else - ok, class loaded by a different thread in parallel.
|
||||
// We should only have found it if it was done loading and ok to use.
|
||||
// The dictionary only holds instance classes, placeholders
|
||||
// also hold array classes.
|
||||
|
||||
assert(check->is_instance_klass(), "noninstance in systemdictionary");
|
||||
if ((defining == true) || (k != check)) {
|
||||
linkage_error1 = "loader (instance of ";
|
||||
linkage_error2 = "): attempted duplicate class definition for name: \"";
|
||||
throwException = true;
|
||||
ss.print("loader %s", java_lang_ClassLoader::describe_external(class_loader()));
|
||||
ss.print(" attempted duplicate %s definition for %s.",
|
||||
k->external_kind(), k->external_name());
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
@ -2156,30 +2167,30 @@ void SystemDictionary::check_constraints(unsigned int d_hash,
|
|||
assert(ph_check == NULL || ph_check == name, "invalid symbol");
|
||||
#endif
|
||||
|
||||
if (linkage_error1 == NULL) {
|
||||
if (throwException == false) {
|
||||
if (constraints()->check_or_update(k, class_loader, name) == false) {
|
||||
linkage_error1 = "loader constraint violation: loader (instance of ";
|
||||
linkage_error2 = ") previously initiated loading for a different type with name \"";
|
||||
throwException = true;
|
||||
ss.print("loader constraint violation: loader %s",
|
||||
java_lang_ClassLoader::describe_external(class_loader()));
|
||||
ss.print(" wants to load %s %s.",
|
||||
k->external_kind(), k->external_name());
|
||||
Klass *existing_klass = constraints()->find_constrained_klass(name, class_loader);
|
||||
if (existing_klass->class_loader() != class_loader()) {
|
||||
ss.print(" A different %s with the same name was previously loaded by %s.",
|
||||
existing_klass->external_kind(),
|
||||
java_lang_ClassLoader::describe_external(existing_klass->class_loader()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Throw error now if needed (cannot throw while holding
|
||||
// SystemDictionary_lock because of rank ordering)
|
||||
|
||||
if (linkage_error1) {
|
||||
ResourceMark rm(THREAD);
|
||||
const char* class_loader_name = loader_name(class_loader());
|
||||
char* type_name = k->name()->as_C_string();
|
||||
size_t buflen = strlen(linkage_error1) + strlen(class_loader_name) +
|
||||
strlen(linkage_error2) + strlen(type_name) + 2; // +2 for '"' and null byte.
|
||||
char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen);
|
||||
jio_snprintf(buf, buflen, "%s%s%s%s\"", linkage_error1, class_loader_name, linkage_error2, type_name);
|
||||
THROW_MSG(vmSymbols::java_lang_LinkageError(), buf);
|
||||
if (throwException == true) {
|
||||
THROW_MSG(vmSymbols::java_lang_LinkageError(), ss.as_string());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Update class loader data dictionary - done after check_constraint and add_to_hierachy
|
||||
// have been called.
|
||||
void SystemDictionary::update_dictionary(unsigned int d_hash,
|
||||
|
|
|
@ -655,13 +655,13 @@ void LinkResolver::check_method_loader_constraints(const LinkInfo& link_info,
|
|||
resolved_loader, true, CHECK);
|
||||
if (failed_type_symbol != NULL) {
|
||||
const char* msg = "loader constraint violation: when resolving %s"
|
||||
" \"%s\" the class loader (instance of %s) of the current class, %s,"
|
||||
" and the class loader (instance of %s) for the method's defining class, %s, have"
|
||||
" \"%s\" the class loader %s of the current class, %s,"
|
||||
" and the class loader %s for the method's defining class, %s, have"
|
||||
" different Class objects for the type %s used in the signature";
|
||||
char* sig = link_info.method_string();
|
||||
const char* loader1_name = SystemDictionary::loader_name(current_loader());
|
||||
const char* loader1_name = java_lang_ClassLoader::describe_external(current_loader());
|
||||
char* current = link_info.current_klass()->name()->as_C_string();
|
||||
const char* loader2_name = SystemDictionary::loader_name(resolved_loader());
|
||||
const char* loader2_name = java_lang_ClassLoader::describe_external(resolved_loader());
|
||||
char* target = resolved_method->method_holder()->name()->as_C_string();
|
||||
char* failed_type_name = failed_type_symbol->as_C_string();
|
||||
size_t buflen = strlen(msg) + strlen(sig) + strlen(loader1_name) +
|
||||
|
@ -688,13 +688,13 @@ void LinkResolver::check_field_loader_constraints(Symbol* field, Symbol* sig,
|
|||
CHECK);
|
||||
if (failed_type_symbol != NULL) {
|
||||
const char* msg = "loader constraint violation: when resolving field"
|
||||
" \"%s\" the class loader (instance of %s) of the referring class, "
|
||||
"%s, and the class loader (instance of %s) for the field's resolved "
|
||||
" \"%s\" the class loader %s of the referring class, "
|
||||
"%s, and the class loader %s for the field's resolved "
|
||||
"type, %s, have different Class objects for that type";
|
||||
char* field_name = field->as_C_string();
|
||||
const char* loader1_name = SystemDictionary::loader_name(ref_loader());
|
||||
const char* loader1_name = java_lang_ClassLoader::describe_external(ref_loader());
|
||||
char* sel = sel_klass->name()->as_C_string();
|
||||
const char* loader2_name = SystemDictionary::loader_name(sel_loader());
|
||||
const char* loader2_name = java_lang_ClassLoader::describe_external(sel_loader());
|
||||
char* failed_type_name = failed_type_symbol->as_C_string();
|
||||
size_t buflen = strlen(msg) + strlen(field_name) + strlen(loader1_name) +
|
||||
strlen(sel) + strlen(loader2_name) + strlen(failed_type_name) + 1;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "precompiled.hpp"
|
||||
#include "jvm.h"
|
||||
#include "classfile/javaClasses.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "interpreter/linkResolver.hpp"
|
||||
|
@ -506,21 +507,21 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, const methodHand
|
|||
CHECK_(false));
|
||||
if (failed_type_symbol != NULL) {
|
||||
const char* msg = "loader constraint violation for class %s: when selecting "
|
||||
"overriding method \"%s\" the class loader (instance of %s) of the "
|
||||
"selected method's type %s, and the class loader (instance of %s) for its super "
|
||||
"overriding method %s the class loader %s of the "
|
||||
"selected method's type %s, and the class loader %s for its super "
|
||||
"type %s have different Class objects for the type %s used in the signature";
|
||||
char* curr_class = klass->name()->as_C_string();
|
||||
char* sig = target_method()->name_and_sig_as_C_string();
|
||||
const char* loader1 = SystemDictionary::loader_name(target_loader());
|
||||
char* sel_class = target_klass->name()->as_C_string();
|
||||
const char* loader2 = SystemDictionary::loader_name(super_loader());
|
||||
char* super_class = super_klass->name()->as_C_string();
|
||||
char* failed_type_name = failed_type_symbol->as_C_string();
|
||||
size_t buflen = strlen(msg) + strlen(curr_class) + strlen(sig) +
|
||||
const char* curr_class = klass->external_name();
|
||||
const char* method = target_method()->name_and_sig_as_C_string();
|
||||
const char* loader1 = java_lang_ClassLoader::describe_external(target_loader());
|
||||
const char* sel_class = target_klass->external_name();
|
||||
const char* loader2 = java_lang_ClassLoader::describe_external(super_loader());
|
||||
const char* super_class = super_klass->external_name();
|
||||
const char* failed_type_name = failed_type_symbol->as_klass_external_name();
|
||||
size_t buflen = strlen(msg) + strlen(curr_class) + strlen(method) +
|
||||
strlen(loader1) + strlen(sel_class) + strlen(loader2) +
|
||||
strlen(super_class) + strlen(failed_type_name);
|
||||
char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen);
|
||||
jio_snprintf(buf, buflen, msg, curr_class, sig, loader1, sel_class, loader2,
|
||||
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);
|
||||
}
|
||||
|
@ -1236,17 +1237,17 @@ void klassItable::initialize_itable_for_interface(int method_table_offset, Klass
|
|||
true, CHECK);
|
||||
if (failed_type_symbol != NULL) {
|
||||
const char* msg = "loader constraint violation in interface itable"
|
||||
" initialization for class %s: when selecting method \"%s\" the"
|
||||
" class loader (instance of %s) for super interface %s, and the class"
|
||||
" loader (instance of %s) of the selected method's type, %s have"
|
||||
" initialization for class %s: when selecting method %s the"
|
||||
" class loader %s for super interface %s, and the class"
|
||||
" loader %s of the selected method's type, %s have"
|
||||
" different Class objects for the type %s used in the signature";
|
||||
char* current = _klass->name()->as_C_string();
|
||||
char* sig = m->name_and_sig_as_C_string();
|
||||
const char* loader1 = SystemDictionary::loader_name(interface_loader());
|
||||
char* iface = InstanceKlass::cast(interf)->name()->as_C_string();
|
||||
const char* loader2 = SystemDictionary::loader_name(method_holder_loader());
|
||||
char* mclass = target()->method_holder()->name()->as_C_string();
|
||||
char* failed_type_name = failed_type_symbol->as_C_string();
|
||||
const char* current = _klass->external_name();
|
||||
const char* sig = m->name_and_sig_as_C_string();
|
||||
const char* loader1 = java_lang_ClassLoader::describe_external(interface_loader());
|
||||
const char* iface = InstanceKlass::cast(interf)->external_name();
|
||||
const char* loader2 = java_lang_ClassLoader::describe_external(method_holder_loader());
|
||||
const char* mclass = target()->method_holder()->external_name();
|
||||
const char* failed_type_name = failed_type_symbol->as_klass_external_name();
|
||||
size_t buflen = strlen(msg) + strlen(current) + strlen(sig) +
|
||||
strlen(loader1) + strlen(iface) + strlen(loader2) + strlen(mclass) +
|
||||
strlen(failed_type_name);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -26,6 +26,8 @@
|
|||
// class C inherits unrelated defaults for m() from types I and J
|
||||
// C is not abstract and does not override abstract method m() in I
|
||||
|
||||
package test;
|
||||
|
||||
super public class C implements I, J version 52:0 {
|
||||
|
||||
public Method "<init>":"()V" stack 1 locals 1 {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -21,4 +21,6 @@
|
|||
* questions.
|
||||
*/
|
||||
|
||||
package test;
|
||||
|
||||
public class Foo {}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -21,6 +21,8 @@
|
|||
* questions.
|
||||
*/
|
||||
|
||||
package test;
|
||||
|
||||
public interface J {
|
||||
public default Foo m() { return null; }
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -27,14 +27,26 @@ import java.io.*;
|
|||
public class PreemptingClassLoader extends ClassLoader {
|
||||
|
||||
private final Set<String> names = new HashSet<>();
|
||||
boolean checkLoaded = true;
|
||||
|
||||
public PreemptingClassLoader(String... names) {
|
||||
for (String n : names) this.names.add(n);
|
||||
}
|
||||
|
||||
public PreemptingClassLoader(String name, String[] names) {
|
||||
super(name, ClassLoader.getSystemClassLoader());
|
||||
for (String n : names) this.names.add(n);
|
||||
}
|
||||
|
||||
public PreemptingClassLoader(String name, String[] names, boolean cL) {
|
||||
super(name, ClassLoader.getSystemClassLoader());
|
||||
for (String n : names) this.names.add(n);
|
||||
checkLoaded = cL;
|
||||
}
|
||||
|
||||
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
|
||||
if (!names.contains(name)) return super.loadClass(name, resolve);
|
||||
Class<?> result = findLoadedClass(name);
|
||||
Class<?> result = checkLoaded ? findLoadedClass(name) : null;
|
||||
if (result == null) {
|
||||
String filename = name.replace('.', '/') + ".class";
|
||||
try (InputStream data = getResourceAsStream(filename)) {
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package test;
|
||||
|
||||
// A simple class to extend an abstract class and get loaded with different
|
||||
// loaders. This class is loaded via Loader2. A similar named class will
|
||||
// be loaded via the bootstrap loader.
|
||||
//
|
||||
// The following code is implemented as java assembler to avoid checks
|
||||
// of javac.
|
||||
//
|
||||
// public class D_ambgs extends bug_21227 {
|
||||
//
|
||||
// D_ambgs() {
|
||||
// System.out.println("Gonna hack this thing");
|
||||
// }
|
||||
//
|
||||
// public D_ambgs[] make(A iface) {
|
||||
// throw new Error("do not call me");
|
||||
// }
|
||||
// }
|
||||
|
||||
class D_ambgs extends C {
|
||||
|
||||
Method D_ambgs:"()V"
|
||||
stack 2 locals 1
|
||||
{
|
||||
aload_0;
|
||||
invokespecial Method test/C."<init>":"()V";
|
||||
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
|
||||
ldc String "Gonna hack this thing";
|
||||
invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
|
||||
return;
|
||||
}
|
||||
|
||||
public Method make:"(Ltest/A;)[Ltest/D_ambgs;"
|
||||
stack 3 locals 2
|
||||
{
|
||||
new class java/lang/Error;
|
||||
dup;
|
||||
ldc String "do not call me";
|
||||
invokespecial Method java/lang/Error."<init>":"(Ljava/lang/String;)V";
|
||||
athrow;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8199852
|
||||
* @summary Test exception messages of LinkageError. Two class loaders load
|
||||
* two different versions of a class. Should trigger exception in
|
||||
* SystemDictionary::check_constraints().
|
||||
* @library /test/lib
|
||||
* @compile D_ambgs.jasm
|
||||
* @run driver ClassFileInstaller test.D_ambgs
|
||||
* @compile ../common/PreemptingClassLoader.java
|
||||
* test/D_ambgs.java Test.java test/B.java
|
||||
* @run driver ClassFileInstaller test.B
|
||||
* @run main/othervm Test
|
||||
*/
|
||||
|
||||
import test.*;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public class Test {
|
||||
|
||||
// Force LinkageError.
|
||||
//
|
||||
// Derived from test runtime/6626217.
|
||||
//
|
||||
// Uses the specialized class loader PreemptingClassLoader.
|
||||
// PreemptingClassLoader only loads files with names passed to it in its
|
||||
// constructor. If it does not find it, it delegates to the super class loader.
|
||||
//
|
||||
// A // interface
|
||||
// |
|
||||
// B // Compiled to the current working directory so that it is found by our
|
||||
// // special class loader. B uses D, so that loading B triggers loading D.
|
||||
//
|
||||
// C // An abstract class.
|
||||
// |
|
||||
// D // Class with two different implementations D1 and D2. D2 is
|
||||
// // compiled to the current working directory so that it is found by our
|
||||
// // special class loader.
|
||||
//
|
||||
// First, the bootstrap loader will load D1. It already has loaded interface A.
|
||||
// Then, the second class loader PreemptingClassLoader will load B. Recursive,
|
||||
// it tries to load interface A. As it does not find it (there is no A.impl2),
|
||||
// it asks the super classloader for A.
|
||||
// Then it loads the D2 variant of D from the current working directory and it's
|
||||
// superclass C. This fails as D1 is already loaded with the same superclass.
|
||||
|
||||
static String expectedErrorMessage =
|
||||
"loader constraint violation: loader \"<unnamed>\" (instance of PreemptingClassLoader, " +
|
||||
"child of \"app\" jdk.internal.loader.ClassLoaders$AppClassLoader) wants to load " +
|
||||
"class test.D_ambgs. A different class with the same name was previously loaded " +
|
||||
"by \"app\" (instance of jdk.internal.loader.ClassLoaders$AppClassLoader).";
|
||||
|
||||
public static void test_access() throws Exception {
|
||||
try {
|
||||
// Make a Class 'D_ambgs' under the default loader.
|
||||
// This uses the implementation from the .java file.
|
||||
C c_1 = new D_ambgs();
|
||||
|
||||
// Some classes under a new Loader, loader2, including, indirectly,
|
||||
// another version of 'D_ambgs'
|
||||
String[] classNames = {"test.B", "test.D_ambgs"};
|
||||
|
||||
ClassLoader loader2 = new PreemptingClassLoader(null, classNames, false);
|
||||
Class class2 = loader2.loadClass("test.B");
|
||||
A iface = (A)class2.newInstance();
|
||||
|
||||
// Call D1.make() loaded by bootstrap loader with B loaded by Loader2.
|
||||
D_ambgs[] x2 = c_1.make(iface);
|
||||
|
||||
throw new RuntimeException("Expected LinkageError was not thrown.");
|
||||
} catch (LinkageError jle) {
|
||||
String errorMsg = jle.getMessage();
|
||||
if (!errorMsg.equals(expectedErrorMessage)) {
|
||||
System.out.println("Expected: " + expectedErrorMessage + "\n" +
|
||||
"but got: " + errorMsg);
|
||||
throw new RuntimeException("Wrong error message of LinkageError.");
|
||||
} else {
|
||||
System.out.println("Passed with message: " + errorMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
test_access();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package test;
|
||||
|
||||
// A simple interface, to allow an unknown foreign call from a class
|
||||
// loaded with the bootstrap loader to a class loaded with Loader2.
|
||||
public interface A {
|
||||
public D_ambgs[] gen();
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package test;
|
||||
|
||||
// This class is loaded via Loader2. Using D_ambgs here will trigger
|
||||
// loading it's second version with Loader2.
|
||||
public class B implements A {
|
||||
public D_ambgs[] gen() {
|
||||
D_ambgs[] x = new D_ambgs[1];
|
||||
x[0] = new D_ambgs();
|
||||
return x;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package test;
|
||||
|
||||
abstract public class C {
|
||||
public abstract D_ambgs[] make(A iface); // abstract factory
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package test;
|
||||
|
||||
// A simple class to extend an abstract class and get loaded with different
|
||||
// loaders. This class is loaded via the bootstrap loader. A similar named class will
|
||||
// be loaded via Loader2.
|
||||
public class D_ambgs extends C {
|
||||
|
||||
// We are loaded by the bootstrap loader. iface is an object of a class
|
||||
// loaded by Loader2. As it references D_ambgs, Loader2 will trigger
|
||||
// loading the version known to it, which differs from this one.
|
||||
public D_ambgs[] make(A iface) {
|
||||
// This function needs to return a value known to be loaded from Loader2.
|
||||
// Since I need to use a yet different loader, I need to make an unknown
|
||||
// foreign call. In this case I'll be using an interface to make the
|
||||
// unknown call, with but a single implementor so the compiler can do the
|
||||
// upcast statically.
|
||||
return iface == null ? null : iface.gen();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8199852
|
||||
* @summary Test exception messages of LinkageError. A class loader loads
|
||||
* twice the same class. Should trigger exception in
|
||||
* SystemDictionary::check_constraints().
|
||||
* @compile ../common/Foo.java
|
||||
* @compile ../common/J.java
|
||||
* ../common/PreemptingClassLoader.java
|
||||
* @run main/othervm Test
|
||||
*/
|
||||
|
||||
public class Test {
|
||||
|
||||
// Check that all names have external formatting ('.' and not '/' in package names).
|
||||
// Check for parent of class loader.
|
||||
static String expectedErrorMessage1 =
|
||||
"loader \"<unnamed>\" (instance of PreemptingClassLoader, " +
|
||||
"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 for name and parent of class loader.
|
||||
static String expectedErrorMessage2 =
|
||||
"loader \"DuplicateLE_Test_Loader\" (instance of PreemptingClassLoader, " +
|
||||
"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 for name and parent of class loader. Type should be mentioned as 'interface'.
|
||||
static String expectedErrorMessage3 =
|
||||
"loader \"DuplicateLE_Test_Loader_IF\" (instance of PreemptingClassLoader, " +
|
||||
"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
|
||||
// detected during vtable creation.
|
||||
//
|
||||
// In this test, during vtable creation for class Task, method "Task.m()LFoo;"
|
||||
// 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
|
||||
// loader constraint check will fail.
|
||||
public static void test(String loaderName, String expectedErrorMessage, String testType) throws Exception {
|
||||
String[] classNames = {testType};
|
||||
ClassLoader l = new PreemptingClassLoader(loaderName, classNames, false);
|
||||
l.loadClass(testType);
|
||||
try {
|
||||
l.loadClass(testType).newInstance();
|
||||
throw new RuntimeException("Expected LinkageError exception not thrown");
|
||||
} catch (LinkageError e) {
|
||||
String errorMsg = e.getMessage();
|
||||
if (!errorMsg.equals(expectedErrorMessage)) {
|
||||
System.out.println("Expected: " + expectedErrorMessage + "\n" +
|
||||
"but got: " + errorMsg);
|
||||
throw new RuntimeException("Wrong LinkageError exception thrown: " + errorMsg);
|
||||
}
|
||||
System.out.println("Passed with message: " + errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
test(null, expectedErrorMessage1, "test.Foo");
|
||||
test("DuplicateLE_Test_Loader", expectedErrorMessage2, "test.Foo");
|
||||
test("DuplicateLE_Test_Loader_IF", expectedErrorMessage3, "test.J");
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -21,6 +21,8 @@
|
|||
* questions.
|
||||
*/
|
||||
|
||||
package test;
|
||||
|
||||
public interface I {
|
||||
public default Foo m() { return null; }
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -21,6 +21,8 @@
|
|||
* questions.
|
||||
*/
|
||||
|
||||
package test;
|
||||
|
||||
public class Task implements Runnable {
|
||||
|
||||
public void run() {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -44,14 +44,14 @@ public class Test {
|
|||
// ICCE). So, no LinkageError exception should be thrown because the loader
|
||||
// constraint check that would cause the LinkageError should not be done.
|
||||
public static void main(String... args) throws Exception {
|
||||
Class<?> c = Foo.class; // forces standard class loader to load Foo
|
||||
ClassLoader l = new PreemptingClassLoader("Task", "Foo", "C", "I");
|
||||
Runnable r = (Runnable) l.loadClass("Task").newInstance();
|
||||
Class<?> c = test.Foo.class; // forces standard class loader to load Foo
|
||||
ClassLoader l = new PreemptingClassLoader("test.Task", "test.Foo", "test.C", "test.I");
|
||||
Runnable r = (Runnable) l.loadClass("test.Task").newInstance();
|
||||
try {
|
||||
r.run(); // Cause an ICCE because both I and J define m()LFoo;
|
||||
throw new RuntimeException("Expected ICCE exception not thrown");
|
||||
} catch (IncompatibleClassChangeError e) {
|
||||
if (!e.getMessage().contains("Conflicting default methods: I.m J.m")) {
|
||||
if (!e.getMessage().contains("Conflicting default methods: test/I.m test/J.m")) {
|
||||
throw new RuntimeException("Wrong ICCE exception thrown: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -21,6 +21,8 @@
|
|||
* questions.
|
||||
*/
|
||||
|
||||
package test;
|
||||
|
||||
public interface I {
|
||||
public Foo m();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -21,6 +21,8 @@
|
|||
* questions.
|
||||
*/
|
||||
|
||||
package test;
|
||||
|
||||
public class Task implements Runnable {
|
||||
|
||||
public void run() {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -23,7 +23,7 @@
|
|||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8186092
|
||||
* @bug 8186092 8199852
|
||||
* @compile ../common/Foo.java
|
||||
* ../common/J.java
|
||||
* I.java
|
||||
|
@ -35,6 +35,26 @@
|
|||
|
||||
public class Test {
|
||||
|
||||
static String expectedErrorMessage1 =
|
||||
"loader constraint violation in interface itable initialization for class test.C: " +
|
||||
"when selecting method test.I.m()Ltest/Foo; " +
|
||||
"the class loader \"<unnamed>\" (instance of PreemptingClassLoader, " +
|
||||
"child of \"app\" jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
"for super interface test.I, and the class 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 =
|
||||
"loader constraint violation in interface itable initialization for class test.C: " +
|
||||
"when selecting method test.I.m()Ltest/Foo; " +
|
||||
"the class loader \"ItableLdrCnstrnt_Test_Loader\" (instance of PreemptingClassLoader, " +
|
||||
"child of \"app\" jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
"for super interface test.I, and the class 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
|
||||
// detected during itable creation.
|
||||
//
|
||||
|
@ -43,18 +63,27 @@ public class Test {
|
|||
// type super interface J. The selected method is not an overpass method nor
|
||||
// otherwise excluded from loader constraint checking. So, a LinkageError
|
||||
// exception should be thrown because the loader constraint check will fail.
|
||||
public static void main(String... args) throws Exception {
|
||||
Class<?> c = Foo.class; // forces standard class loader to load Foo
|
||||
ClassLoader l = new PreemptingClassLoader("Task", "Foo", "C", "I");
|
||||
Runnable r = (Runnable) l.loadClass("Task").newInstance();
|
||||
public static void test(String loaderName, String expectedErrorMessage) throws Exception {
|
||||
Class<?> c = test.Foo.class; // Forces standard class loader to load Foo.
|
||||
String[] classNames = {"test.Task", "test.Foo", "test.C", "test.I"};
|
||||
ClassLoader l = new PreemptingClassLoader(loaderName, classNames);
|
||||
Runnable r = (Runnable) l.loadClass("test.Task").newInstance();
|
||||
try {
|
||||
r.run();
|
||||
throw new RuntimeException("Expected LinkageError exception not thrown");
|
||||
} catch (LinkageError e) {
|
||||
if (!e.getMessage().contains(
|
||||
"loader constraint violation in interface itable initialization for class C:")) {
|
||||
throw new RuntimeException("Wrong LinkageError exception thrown: " + e.getMessage());
|
||||
String errorMsg = e.getMessage();
|
||||
if (!errorMsg.equals(expectedErrorMessage)) {
|
||||
System.out.println("Expected: " + expectedErrorMessage + "\n" +
|
||||
"but got: " + errorMsg);
|
||||
throw new RuntimeException("Wrong LinkageError exception thrown: " + errorMsg);
|
||||
}
|
||||
System.out.println("Passed with message: " + errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
test(null, expectedErrorMessage1);
|
||||
test("ItableLdrCnstrnt_Test_Loader", expectedErrorMessage2);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -21,6 +21,8 @@
|
|||
* questions.
|
||||
*/
|
||||
|
||||
package test;
|
||||
|
||||
public interface I extends J {
|
||||
public Foo m();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -21,4 +21,6 @@
|
|||
* questions.
|
||||
*/
|
||||
|
||||
package test;
|
||||
|
||||
public class Task extends C { }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -48,16 +48,16 @@ public class Test {
|
|||
// because the loader constraint check that would cause the LinkageError
|
||||
// should not be done.
|
||||
public static void main(String args[]) throws Exception {
|
||||
Class<?> c = Foo.class; // forces standard class loader to load Foo
|
||||
ClassLoader l = new PreemptingClassLoader("Task", "Foo", "I", "J");
|
||||
l.loadClass("Foo");
|
||||
l.loadClass("Task").newInstance();
|
||||
Task t = new Task();
|
||||
Class<?> c = test.Foo.class; // forces standard class loader to load Foo
|
||||
ClassLoader l = new PreemptingClassLoader("test.Task", "test.Foo", "test.I", "test.J");
|
||||
l.loadClass("test.Foo");
|
||||
l.loadClass("test.Task").newInstance();
|
||||
test.Task t = new test.Task();
|
||||
try {
|
||||
t.m(); // Should get AME
|
||||
throw new RuntimeException("Missing AbstractMethodError exception");
|
||||
} catch (AbstractMethodError e) {
|
||||
if (!e.getMessage().contains("Method Task.m()LFoo; is abstract")) {
|
||||
if (!e.getMessage().contains("Method test/Task.m()Ltest/Foo; is abstract")) {
|
||||
throw new RuntimeException("Wrong AME exception thrown: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -21,5 +21,7 @@
|
|||
* questions.
|
||||
*/
|
||||
|
||||
package test;
|
||||
|
||||
public interface I extends J {
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -21,6 +21,8 @@
|
|||
* questions.
|
||||
*/
|
||||
|
||||
package test;
|
||||
|
||||
public class Task extends C {
|
||||
|
||||
public Foo m() {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -23,7 +23,7 @@
|
|||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8186092
|
||||
* @bug 8186092 8199852
|
||||
* @compile ../common/Foo.java
|
||||
* ../common/J.java
|
||||
* I.java
|
||||
|
@ -35,6 +35,26 @@
|
|||
|
||||
public class Test {
|
||||
|
||||
static String expectedErrorMessage1 =
|
||||
"loader constraint violation for class test.Task: " +
|
||||
"when selecting overriding method test.Task.m()Ltest/Foo; " +
|
||||
"the class loader \"<unnamed>\" (instance of PreemptingClassLoader, " +
|
||||
"child of \"app\" jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
"of the selected method's type test.Task, " +
|
||||
"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 =
|
||||
"loader constraint violation for class test.Task: " +
|
||||
"when selecting overriding method test.Task.m()Ltest/Foo; " +
|
||||
"the class loader \"VtableLdrCnstrnt_Test_Loader\" (instance of PreemptingClassLoader, " +
|
||||
"child of \"app\" jdk.internal.loader.ClassLoaders$AppClassLoader) " +
|
||||
"of the selected method's type test.Task, " +
|
||||
"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
|
||||
// detected during vtable creation.
|
||||
//
|
||||
|
@ -42,22 +62,28 @@ public class Test {
|
|||
// 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
|
||||
// loader constraint check will fail.
|
||||
public static void main(String args[]) throws Exception {
|
||||
Class<?> c = Foo.class; // forces standard class loader to load Foo
|
||||
ClassLoader l = new PreemptingClassLoader("Task", "Foo", "I");
|
||||
l.loadClass("Foo");
|
||||
public static void test(String loaderName, String expectedErrorMessage) throws Exception {
|
||||
Class<?> c = test.Foo.class; // Forces standard class loader to load Foo.
|
||||
String[] classNames = {"test.Task", "test.Foo", "test.I"};
|
||||
ClassLoader l = new PreemptingClassLoader(loaderName, classNames);
|
||||
l.loadClass("test.Foo");
|
||||
try {
|
||||
l.loadClass("Task").newInstance();
|
||||
l.loadClass("test.Task").newInstance();
|
||||
throw new RuntimeException("Expected LinkageError exception not thrown");
|
||||
} catch (LinkageError e) {
|
||||
if (!e.getMessage().contains(
|
||||
"loader constraint violation for class Task: when selecting overriding method") ||
|
||||
!e.getMessage().contains(
|
||||
"for its super type J have different Class objects for the type Foo")) {
|
||||
throw new RuntimeException("Wrong LinkageError exception thrown: " + e.getMessage());
|
||||
String errorMsg = e.getMessage();
|
||||
if (!errorMsg.equals(expectedErrorMessage)) {
|
||||
System.out.println("Expected: " + expectedErrorMessage + "\n" +
|
||||
"but got: " + errorMsg);
|
||||
throw new RuntimeException("Wrong LinkageError exception thrown: " + errorMsg);
|
||||
}
|
||||
System.out.println("Passed with message: " + errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
test(null, expectedErrorMessage1);
|
||||
test("VtableLdrCnstrnt_Test_Loader", expectedErrorMessage2);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue