8199852: Print more information about class loaders in LinkageErrors

Reviewed-by: dholmes, lfoltan, gtriantafill
This commit is contained in:
Goetz Lindenmaier 2018-05-07 11:38:21 +02:00
parent 5f40eda733
commit 72a2ac8b8b
28 changed files with 660 additions and 97 deletions

View file

@ -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) \

View file

@ -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);
};

View file

@ -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,

View file

@ -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;

View file

@ -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);

View file

@ -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 {

View file

@ -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 {}

View file

@ -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; }
}

View file

@ -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)) {

View file

@ -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;
}
}

View file

@ -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();
}
}

View file

@ -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();
}

View file

@ -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;
}
}

View file

@ -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
}

View file

@ -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();
}
}

View file

@ -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");
}
}

View file

@ -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; }
}

View file

@ -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() {

View file

@ -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());
}
}

View file

@ -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();
}

View file

@ -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() {

View file

@ -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);
}
}

View file

@ -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();
}

View file

@ -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 { }

View file

@ -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());
}
}

View file

@ -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 {
}

View file

@ -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() {

View file

@ -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);
}
}