8202913: loader constraint message for fields specifies incorrect referring class
Summary: Improve the message to display the right referring class.
Reviewed-by: acorn, goetz, dholmes
--- a/src/hotspot/share/interpreter/linkResolver.cpp Thu May 31 07:05:10 2018 -0700
+++ b/src/hotspot/share/interpreter/linkResolver.cpp Thu May 31 10:38:06 2018 -0400
@@ -688,19 +688,21 @@
CHECK);
if (failed_type_symbol != NULL) {
const char* msg = "loader constraint violation: when resolving field"
- " \"%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();
+ " \"%s\" of type %s, the class loader %s of the current class, "
+ "%s, and the class loader %s for the field's defining "
+ "type, %s, have different Class objects for type %s";
+ const char* field_name = field->as_C_string();
const char* loader1_name = java_lang_ClassLoader::describe_external(ref_loader());
- char* sel = sel_klass->name()->as_C_string();
+ const char* sel = sel_klass->external_name();
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;
+ const char* failed_type_name = failed_type_symbol->as_klass_external_name();
+ const char* curr_klass_name = current_klass->external_name();
+ size_t buflen = strlen(msg) + strlen(field_name) + 2 * strlen(failed_type_name) +
+ strlen(loader1_name) + strlen(curr_klass_name) +
+ strlen(loader2_name) + strlen(sel) + 1;
char* buf = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, buflen);
- jio_snprintf(buf, buflen, msg, field_name, loader1_name, sel, loader2_name,
- failed_type_name);
+ jio_snprintf(buf, buflen, msg, field_name, failed_type_name, loader1_name,
+ curr_klass_name, loader2_name, sel, failed_type_name);
THROW_MSG(vmSymbols::java_lang_LinkageError(), buf);
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/LoaderConstraints/ldrCnstrFldMsg/LdrCnstrFldMsgTest.java Thu May 31 10:38:06 2018 -0400
@@ -0,0 +1,60 @@
+/*
+ * 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
+ * @compile pkg/Grand.java pkg/Parent.java pkg/ClassLoaderForParentFoo.java
+ * @compile pkg/ClassLoaderForChildGrandFoo.java pkg/Child.jasm
+ * @run main/othervm LdrCnstrFldMsgTest
+ */
+
+import java.lang.reflect.Method;
+
+// Check that LinkageError loader constraint message for fields contains the
+// correct information.
+//
+// The test creates two class loaders. The first class loader loads classes
+// Child, Foo, and Grand. The second class loader loads Parent and Foo. Class
+// Parent is a sub-class of Grand and class Child is a sub-class of Parent.
+// Class Child tries to load Parent._field1. This should fail because type Foo
+// for Parent._field1 is a different type than Child's Foo.
+//
+public class LdrCnstrFldMsgTest {
+ public static void main(String... args) throws Exception {
+ ClassLoader l = new pkg.ClassLoaderForChildGrandFoo("pkg.Foo", "pkg.Child", "pkg.Grand");
+ l.loadClass("pkg.Foo");
+
+ // Try to call a public method in Grand.
+ Runnable r = (Runnable) l.loadClass("pkg.Child").newInstance();
+ try {
+ r.run();
+ throw new RuntimeException("Expected LinkageError exception not thrown");
+ } catch (java.lang.LinkageError e) {
+ if (!e.getMessage().contains("for the field's defining type, pkg.Parent,") ||
+ !e.getMessage().contains("have different Class objects for type pkg.Foo")) {
+ throw new RuntimeException("Wrong LinkageError exception thrown: " + e.toString());
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/LoaderConstraints/ldrCnstrFldMsg/pkg/Child.jasm Thu May 31 10:38:06 2018 -0400
@@ -0,0 +1,50 @@
+/*
+ * 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 pkg;
+
+// The getfield of Parent._field1 gets a LinkageError because class Parent
+// has a different Foo class than Child, causing a loader constraint violation.
+super public class Child extends pkg/Parent implements java/lang/Runnable version 50:0 {
+
+ public Method "<init>":"()V" stack 1 locals 1 {
+ aload_0;
+ invokespecial Method pkg/Parent."<init>":"()V";
+ return;
+ }
+
+ public Method run:"()V" stack 4 locals 4 {
+ ldc class pkg/Foo;
+ astore_1;
+ new class pkg/Child;
+ dup;
+ invokespecial Method pkg/Child."<init>":"()V";
+ astore_2;
+ aload_2;
+ getstatic Field pkg/Parent._field1:"Lpkg/Foo;";
+ pop;
+ return;
+ }
+
+} // end Class Child
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/LoaderConstraints/ldrCnstrFldMsg/pkg/ClassLoaderForChildGrandFoo.java Thu May 31 10:38:06 2018 -0400
@@ -0,0 +1,73 @@
+/*
+ * 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 pkg;
+
+import java.util.*;
+import java.io.*;
+
+// This class loader loads Foo, Child, and Grand.
+public class ClassLoaderForChildGrandFoo extends ClassLoader {
+
+ ClassLoader l2 = null;
+
+ private final Set<String> names = new HashSet<>();
+
+ public ClassLoaderForChildGrandFoo(String... names) {
+ for (String n : names) this.names.add(n);
+ }
+
+ protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ // Create class loader l2 to load Parent and Foo. And, pass this class
+ // loader to l2 so l2 can use it to load Grand.
+ if (name.contains("Parent") && l2 == null) {
+ l2 = new ClassLoaderForParentFoo(this, "pkg.Foo", "pkg.Grand", "pkg.Parent");
+ Class<?> b = l2.loadClass("pkg.Parent");
+ return b;
+ }
+ if (!names.contains(name)) return super.loadClass(name, resolve);
+ Class<?> result = findLoadedClass(name);
+
+ if (result == null) {
+ String filename = name.replace('.', '/') + ".class";
+ try (InputStream data = getResourceAsStream(filename)) {
+ if (data == null) throw new ClassNotFoundException();
+ try (ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {
+ int b;
+ do {
+ b = data.read();
+ if (b >= 0) buffer.write(b);
+ } while (b >= 0);
+ byte[] bytes = buffer.toByteArray();
+ result = defineClass(name, bytes, 0, bytes.length);
+ }
+ } catch (IOException e) {
+ throw new ClassNotFoundException("Error reading class file", e);
+ }
+ }
+ if (resolve) resolveClass(result);
+ return result;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/LoaderConstraints/ldrCnstrFldMsg/pkg/ClassLoaderForParentFoo.java Thu May 31 10:38:06 2018 -0400
@@ -0,0 +1,69 @@
+/*
+ * 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 pkg;
+
+import java.util.*;
+import java.io.*;
+
+// This class loader loads Foo and Parent and calls back to l1 to load Grand.
+public class ClassLoaderForParentFoo extends ClassLoader {
+
+ private final Set<String> names = new HashSet<>();
+
+ ClassLoader l1;
+
+ public ClassLoaderForParentFoo(ClassLoader l, String... names) {
+ l1 = l;
+ for (String n : names) this.names.add(n);
+ }
+
+ protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+ if (name.contains("Grand")) return l1.loadClass("pkg.Grand");
+ if (!names.contains(name)) return super.loadClass(name, resolve);
+ Class<?> result = findLoadedClass(name);
+ if (result == null) {
+ // Load our own version of Foo that will be referenced by Parent.
+ if (name.contains("Parent")) loadClass("pkg.Foo", resolve);
+ String filename = name.replace('.', '/') + ".class";
+ try (InputStream data = getResourceAsStream(filename)) {
+ if (data == null) throw new ClassNotFoundException();
+ try (ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {
+ int b;
+ do {
+ b = data.read();
+ if (b >= 0) buffer.write(b);
+ } while (b >= 0);
+ byte[] bytes = buffer.toByteArray();
+ result = defineClass(name, bytes, 0, bytes.length);
+ }
+ } catch (IOException e) {
+ throw new ClassNotFoundException("Error reading class file", e);
+ }
+ }
+ if (resolve) resolveClass(result);
+ return result;
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/LoaderConstraints/ldrCnstrFldMsg/pkg/Foo.java Thu May 31 10:38:06 2018 -0400
@@ -0,0 +1,27 @@
+/*
+ * 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 pkg;
+
+public class Foo {}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/LoaderConstraints/ldrCnstrFldMsg/pkg/Grand.java Thu May 31 10:38:06 2018 -0400
@@ -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 pkg;
+
+public class Grand {
+ public static Foo _field1;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/LoaderConstraints/ldrCnstrFldMsg/pkg/Parent.java Thu May 31 10:38:06 2018 -0400
@@ -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 pkg;
+
+public class Parent extends Grand {
+ public static Foo _field1;
+}