8202913: loader constraint message for fields specifies incorrect referring class
authorhseigel
Thu, 31 May 2018 10:38:06 -0400
changeset 50325 462453f3c7f6
parent 50323 25d711fca885
child 50326 ec55eadfc2ab
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
src/hotspot/share/interpreter/linkResolver.cpp
test/hotspot/jtreg/runtime/LoaderConstraints/ldrCnstrFldMsg/LdrCnstrFldMsgTest.java
test/hotspot/jtreg/runtime/LoaderConstraints/ldrCnstrFldMsg/pkg/Child.jasm
test/hotspot/jtreg/runtime/LoaderConstraints/ldrCnstrFldMsg/pkg/ClassLoaderForChildGrandFoo.java
test/hotspot/jtreg/runtime/LoaderConstraints/ldrCnstrFldMsg/pkg/ClassLoaderForParentFoo.java
test/hotspot/jtreg/runtime/LoaderConstraints/ldrCnstrFldMsg/pkg/Foo.java
test/hotspot/jtreg/runtime/LoaderConstraints/ldrCnstrFldMsg/pkg/Grand.java
test/hotspot/jtreg/runtime/LoaderConstraints/ldrCnstrFldMsg/pkg/Parent.java
--- 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;
+}