8199940: Print more information about class loaders in IllegalAccessErrors.
authorgoetz
Wed, 27 Jun 2018 09:52:23 +0200
changeset 50816 a73848f8d0ad
parent 50815 54a285a5c6cb
child 50817 fa1e04811ff6
8199940: Print more information about class loaders in IllegalAccessErrors. Reviewed-by: lfoltan, mchung
src/hotspot/share/classfile/classFileParser.cpp
src/hotspot/share/interpreter/linkResolver.cpp
test/hotspot/jtreg/runtime/Nestmates/membership/TestNestmateMembership.java
test/hotspot/jtreg/runtime/Nestmates/privateConstructors/TestConstructorHierarchy.java
test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE78_A.java
test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE78_B.java
test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE_Loader1.java
test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE_Loader2.java
test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IllegalAccessErrorTest.java
test/hotspot/jtreg/runtime/modules/AccessCheck/ExpQualToM1PrivateMethodIAE.java
--- a/src/hotspot/share/classfile/classFileParser.cpp	Wed Jun 27 12:46:15 2018 +0200
+++ b/src/hotspot/share/classfile/classFileParser.cpp	Wed Jun 27 09:52:23 2018 +0200
@@ -4612,12 +4612,17 @@
                                                       InstanceKlass::cast(super),
                                                       vca_result);
       if (msg == NULL) {
+        bool same_module = (this_klass->module() == super->module());
         Exceptions::fthrow(
           THREAD_AND_LOCATION,
           vmSymbols::java_lang_IllegalAccessError(),
-          "class %s cannot access its superclass %s",
+          "class %s cannot access its %ssuperclass %s (%s%s%s)",
           this_klass->external_name(),
-          super->external_name());
+          super->is_abstract() ? "abstract " : "",
+          super->external_name(),
+          (same_module) ? this_klass->joint_in_module_of_loader(super) : this_klass->class_in_module_of_loader(),
+          (same_module) ? "" : "; ",
+          (same_module) ? "" : super->class_in_module_of_loader());
       } else {
         // Add additional message content.
         Exceptions::fthrow(
@@ -4646,12 +4651,16 @@
                                                       InstanceKlass::cast(k),
                                                       vca_result);
       if (msg == NULL) {
+        bool same_module = (this_klass->module() == k->module());
         Exceptions::fthrow(
           THREAD_AND_LOCATION,
           vmSymbols::java_lang_IllegalAccessError(),
-          "class %s cannot access its superinterface %s",
+          "class %s cannot access its superinterface %s (%s%s%s)",
           this_klass->external_name(),
-          k->external_name());
+          k->external_name(),
+          (same_module) ? this_klass->joint_in_module_of_loader(k) : this_klass->class_in_module_of_loader(),
+          (same_module) ? "" : "; ",
+          (same_module) ? "" : k->class_in_module_of_loader());
       } else {
         // Add additional message content.
         Exceptions::fthrow(
--- a/src/hotspot/share/interpreter/linkResolver.cpp	Wed Jun 27 12:46:15 2018 +0200
+++ b/src/hotspot/share/interpreter/linkResolver.cpp	Wed Jun 27 09:52:23 2018 +0200
@@ -218,7 +218,7 @@
     fatal("Unexpected call kind %d", call_kind());
   }
 }
-#endif //ASSERT
+#endif // ASSERT
 
 #ifndef PRODUCT
 void CallInfo::print() {
@@ -294,7 +294,7 @@
       base_klass = ObjArrayKlass::cast(sel_klass)->bottom_klass();
     }
     // The element type could be a typeArray - we only need the access
-    // check if it is an reference to another class.
+    // check if it is a reference to another class.
     if (!base_klass->is_instance_klass()) {
       return;  // no relevant check to do
     }
@@ -306,13 +306,17 @@
     char* msg = Reflection::verify_class_access_msg(ref_klass,
                                                     InstanceKlass::cast(base_klass),
                                                     vca_result);
+    bool same_module = (base_klass->module() == ref_klass->module());
     if (msg == NULL) {
       Exceptions::fthrow(
         THREAD_AND_LOCATION,
         vmSymbols::java_lang_IllegalAccessError(),
-        "failed to access class %s from class %s",
+        "failed to access class %s from class %s (%s%s%s)",
         base_klass->external_name(),
-        ref_klass->external_name());
+        ref_klass->external_name(),
+        (same_module) ? base_klass->joint_in_module_of_loader(ref_klass) : base_klass->class_in_module_of_loader(),
+        (same_module) ? "" : "; ",
+        (same_module) ? "" : ref_klass->class_in_module_of_loader());
     } else {
       // Use module specific message returned by verify_class_access_msg().
       Exceptions::fthrow(
@@ -596,8 +600,11 @@
     Exceptions::fthrow(
       THREAD_AND_LOCATION,
       vmSymbols::java_lang_IllegalAccessError(),
-      "class %s tried to access method %s.%s%s (%s%s%s)",
+      "class %s tried to access %s%s%smethod %s.%s%s (%s%s%s)",
       ref_klass->external_name(),
+      sel_method->is_abstract()  ? "abstract "  : "",
+      sel_method->is_protected() ? "protected " : "",
+      sel_method->is_private()   ? "private "   : "",
       sel_klass->external_name(),
       sel_method->name()->as_C_string(),
       sel_method->signature()->as_C_string(),
@@ -927,14 +934,20 @@
   // Any existing exceptions that may have been thrown, for example LinkageErrors
   // from nest-host resolution, have been allowed to propagate.
   if (!can_access) {
+    bool same_module = (sel_klass->module() == ref_klass->module());
     ResourceMark rm(THREAD);
     Exceptions::fthrow(
       THREAD_AND_LOCATION,
       vmSymbols::java_lang_IllegalAccessError(),
-      "tried to access field %s.%s from class %s",
+      "class %s tried to access %s%sfield %s.%s (%s%s%s)",
+      ref_klass->external_name(),
+      fd.is_protected() ? "protected " : "",
+      fd.is_private()   ? "private "   : "",
       sel_klass->external_name(),
       fd.name()->as_C_string(),
-      ref_klass->external_name()
+      (same_module) ? ref_klass->joint_in_module_of_loader(sel_klass) : ref_klass->class_in_module_of_loader(),
+      (same_module) ? "" : "; ",
+      (same_module) ? "" : sel_klass->class_in_module_of_loader()
     );
     return;
   }
--- a/test/hotspot/jtreg/runtime/Nestmates/membership/TestNestmateMembership.java	Wed Jun 27 12:46:15 2018 +0200
+++ b/test/hotspot/jtreg/runtime/Nestmates/membership/TestNestmateMembership.java	Wed Jun 27 09:52:23 2018 +0200
@@ -671,7 +671,7 @@
     static void test_NoHostInvoke() throws Throwable {
         System.out.println("Testing for missing nest-host attribute");
         String msg = "class TestNestmateMembership$Caller tried to access " +
-            "method TestNestmateMembership$TargetNoHost.m()V";
+            "private method TestNestmateMembership$TargetNoHost.m()V";
         try {
             Caller.invokeTargetNoHost();
             throw new Error("Missing IllegalAccessError: " + msg);
@@ -698,7 +698,7 @@
         }
 
         msg = "class TestNestmateMembership$CallerNoHost tried to access " +
-            "method TestNestmateMembership$Target.m()V";
+            "private method TestNestmateMembership$Target.m()V";
         try {
             CallerNoHost.invokeTarget();
             throw new Error("Missing IllegalAccessError: " + msg);
@@ -706,8 +706,8 @@
         catch (IllegalAccessError expected) {
             check_expected(expected, msg);
         }
-        msg = "class TestNestmateMembership$CallerNoHost tried to access method " +
-            "TestNestmateMembership$TargetNoHost.m()V";
+        msg = "class TestNestmateMembership$CallerNoHost tried to access private " +
+            "method TestNestmateMembership$TargetNoHost.m()V";
         try {
             CallerNoHost.invokeTargetNoHost();
             throw new Error("Missing IllegalAccessError: " + msg);
@@ -949,8 +949,8 @@
 
     static void test_NoHostConstruct() throws Throwable {
         System.out.println("Testing for missing nest-host attribute");
-        String msg = "class TestNestmateMembership$Caller tried to access method " +
-            "TestNestmateMembership$TargetNoHost.<init>()V";
+        String msg = "class TestNestmateMembership$Caller tried to access private " +
+            "method TestNestmateMembership$TargetNoHost.<init>()V";
         try {
             Caller.newTargetNoHost();
             throw new Error("Missing IncompatibleClassChangeError: " + msg);
@@ -976,8 +976,8 @@
             check_expected(expected, msg);
         }
 
-        msg = "class TestNestmateMembership$CallerNoHost tried to access method " +
-            "TestNestmateMembership$Target.<init>()V";
+        msg = "class TestNestmateMembership$CallerNoHost tried to access private " +
+            "method TestNestmateMembership$Target.<init>()V";
         try {
             CallerNoHost.newTarget();
             throw new Error("Missing IncompatibleClassChangeError: " + msg);
@@ -985,8 +985,8 @@
         catch (IncompatibleClassChangeError expected) {
             check_expected(expected, msg);
         }
-        msg = "class TestNestmateMembership$CallerNoHost tried to access method " +
-            "TestNestmateMembership$TargetNoHost.<init>()V";
+        msg = "class TestNestmateMembership$CallerNoHost tried to access private " +
+            "method TestNestmateMembership$TargetNoHost.<init>()V";
         try {
             CallerNoHost.newTargetNoHost();
             throw new Error("Missing IncompatibleClassChangeError: " + msg);
@@ -1220,8 +1220,8 @@
 
     static void test_NoHostGetField() throws Throwable {
         System.out.println("Testing for missing nest-host attribute");
-        String msg = "tried to access field TestNestmateMembership$TargetNoHost.f" +
-            " from class TestNestmateMembership$Caller";
+        String msg = "class TestNestmateMembership$Caller tried to access private " +
+            "field TestNestmateMembership$TargetNoHost.f";
         try {
             Caller.getFieldTargetNoHost();
             throw new Error("Missing IncompatibleClassChangeError: " + msg);
@@ -1247,8 +1247,8 @@
             check_expected(expected, msg);
         }
 
-        msg = "tried to access field TestNestmateMembership$Target.f" +
-            " from class TestNestmateMembership$CallerNoHost";
+        msg = "class TestNestmateMembership$CallerNoHost tried to access private " +
+            "field TestNestmateMembership$Target.f";
         try {
             CallerNoHost.getFieldTarget();
             throw new Error("Missing IncompatibleClassChangeError: " + msg);
@@ -1256,8 +1256,8 @@
         catch (IncompatibleClassChangeError expected) {
             check_expected(expected, msg);
         }
-        msg = "tried to access field TestNestmateMembership$TargetNoHost.f" +
-            " from class TestNestmateMembership$CallerNoHost";
+        msg = "class TestNestmateMembership$CallerNoHost tried to access private " +
+            "field TestNestmateMembership$TargetNoHost.f";
         try {
             CallerNoHost.getFieldTargetNoHost();
             throw new Error("Missing IncompatibleClassChangeError: " + msg);
@@ -1485,8 +1485,8 @@
 
     static void test_NoHostPutField() throws Throwable {
         System.out.println("Testing for missing nest-host attribute");
-        String msg = "tried to access field TestNestmateMembership$TargetNoHost.f" +
-            " from class TestNestmateMembership$Caller";
+        String msg = "class TestNestmateMembership$Caller tried to access private " +
+            "field TestNestmateMembership$TargetNoHost.f";
         try {
             Caller.putFieldTargetNoHost();
             throw new Error("Missing IncompatibleClassChangeError: " + msg);
@@ -1512,8 +1512,8 @@
             check_expected(expected, msg);
         }
 
-        msg = "tried to access field TestNestmateMembership$Target.f" +
-            " from class TestNestmateMembership$CallerNoHost";
+        msg = "class TestNestmateMembership$CallerNoHost tried to access private " +
+            "field TestNestmateMembership$Target.f";
         try {
             CallerNoHost.putFieldTarget();
             throw new Error("Missing IncompatibleClassChangeError: " + msg);
@@ -1521,8 +1521,8 @@
         catch (IncompatibleClassChangeError expected) {
             check_expected(expected, msg);
         }
-        msg = "tried to access field TestNestmateMembership$TargetNoHost.f" +
-            " from class TestNestmateMembership$CallerNoHost";
+        msg = "class TestNestmateMembership$CallerNoHost tried to access private " +
+            "field TestNestmateMembership$TargetNoHost.f";
         try {
             CallerNoHost.putFieldTargetNoHost();
             throw new Error("Missing IncompatibleClassChangeError: " + msg);
--- a/test/hotspot/jtreg/runtime/Nestmates/privateConstructors/TestConstructorHierarchy.java	Wed Jun 27 12:46:15 2018 +0200
+++ b/test/hotspot/jtreg/runtime/Nestmates/privateConstructors/TestConstructorHierarchy.java	Wed Jun 27 09:52:23 2018 +0200
@@ -51,7 +51,7 @@
             throw new Error("Unexpected construction of ExternalSuper");
         }
         catch (IllegalAccessError iae) {
-            if (iae.getMessage().contains("class TestConstructorHierarchy tried to access method ExternalSuper.<init>()V")) {
+            if (iae.getMessage().contains("class TestConstructorHierarchy tried to access private method ExternalSuper.<init>()V")) {
                 System.out.println("Got expected exception constructing ExternalSuper: " + iae);
             }
             else throw new Error("Unexpected IllegalAccessError: " + iae);
@@ -61,7 +61,7 @@
             throw new Error("Unexpected construction of NestedA and supers");
         }
         catch (IllegalAccessError iae) {
-            if (iae.getMessage().contains("class TestConstructorHierarchy$NestedA tried to access method ExternalSuper.<init>()V")) {
+            if (iae.getMessage().contains("class TestConstructorHierarchy$NestedA tried to access private method ExternalSuper.<init>()V")) {
                 System.out.println("Got expected exception constructing NestedA: " + iae);
             }
             else throw new Error("Unexpected IllegalAccessError: " + iae);
@@ -71,7 +71,7 @@
             throw new Error("Unexpected construction of ExternalSub");
         }
         catch (IllegalAccessError iae) {
-            if (iae.getMessage().contains("class ExternalSub tried to access method TestConstructorHierarchy$NestedA.<init>()V")) {
+            if (iae.getMessage().contains("class ExternalSub tried to access private method TestConstructorHierarchy$NestedA.<init>()V")) {
                 System.out.println("Got expected exception constructing ExternalSub: " + iae);
             }
             else throw new Error("Unexpected IllegalAccessError: " + iae);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE78_A.java	Wed Jun 27 09:52:23 2018 +0200
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2018 by SAP AG, Walldorf, Germany.
+ * 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;
+
+public class IAE78_A {
+
+    static Object f = new Object();
+
+    IAE78_A() {
+        // Nothing to do.
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE78_B.java	Wed Jun 27 09:52:23 2018 +0200
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ *
+ */
+
+package test;
+
+public class IAE78_B {
+
+    public static void create() {
+        new IAE78_A();
+    }
+
+    public static void access() {
+        IAE78_A.f.hashCode();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IAE_Loader1.java	Wed Jun 27 09:52:23 2018 +0200
@@ -0,0 +1,59 @@
+/*
+ * 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;
+
+import java.util.*;
+import java.io.*;
+
+public class IAE_Loader1 extends ClassLoader {
+
+    private final Set<String> names = new HashSet<>();
+
+    public IAE_Loader1(String name, String[] names) {
+        super(name, ClassLoader.getSystemClassLoader());
+        for (String n : names) this.names.add(n);
+    }
+
+    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+        if (!names.contains(name)) {
+            return super.loadClass(name, resolve);
+        }
+        String filename = name.replace('.', '/') + ".class";
+        Class<?> result = null;
+        try (InputStream data = getResourceAsStream(filename)) {
+            if (data == null) {
+                throw new ClassNotFoundException();
+            }
+            try (ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {
+                byte[] bytes = data.readAllBytes();
+                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/exceptionMsgs/IllegalAccessError/IAE_Loader2.java	Wed Jun 27 09:52:23 2018 +0200
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2018 by SAP AG, Walldorf, Germany.
+ * 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.SecureClassLoader;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.stream.Collectors;
+
+/**
+ * This is a class loader which can load the same classes as another class loader.
+ * <p>
+ * This is mainly useful for tests when you want to load a class, but do it with a class
+ * loader you can dispose. The clone loader just asks the loader to be cloned to get
+ * the bytecodes, but defines the class itself.
+ * <p>
+ * Additionally you can specify a set of classes the loader should not be able to load.
+ */
+public class IAE_Loader2 extends SecureClassLoader {
+
+    /**
+     * The class loaded to clone.
+     */
+    private final ClassLoader toClone;
+
+    /**
+     * The strings we cannot load.
+     */
+    private final HashSet<String> notLoadable;
+
+    /**
+     * The strings we just delegate.
+     */
+    private final HashSet<String> simpleDelegate;
+
+    /**
+     * Creates a class loader which can load the same classes as the loader which
+     * loaded the <code>IAE_Loader2</code> class itself.
+     * <p>
+     * Only the classes which are loadable by the 'parent' loader are delegated to that
+     * loader (to make it possible mix classes).
+     *
+     * @param name the name of the class loader.
+     * @param parent the parent loader which is first asked to load a class.
+     * @param toClone the class loader to mimic. The clone class loader will be able to
+     *                load the same classes as the 'toClone' loader.
+     * @param notLoadable The classes we should not be able to load via this loader.
+     * @param simpleDelegate The names of the classes for which we simply delegate.
+     */
+    public IAE_Loader2(String name, ClassLoader parent, ClassLoader toClone,
+                       String[] notLoadable, String[] simpleDelegate) {
+        super(name, parent);
+
+        this.toClone = toClone;
+        this.notLoadable    = Arrays.stream(notLoadable).collect(Collectors.toCollection(HashSet<String>::new));
+        this.simpleDelegate = Arrays.stream(simpleDelegate).collect(Collectors.toCollection(HashSet<String>::new));
+    }
+
+    /**
+     * @see java.lang.ClassLoader#findClass(java.lang.String)
+     */
+    @Override
+    protected Class<?> findClass(String name) throws ClassNotFoundException {
+        if (notLoadable.contains(name)) {
+            throw new ClassNotFoundException("The clone class loader explicitely " +
+                    "didn't found the class");
+        }
+
+        if (simpleDelegate.contains(name)) {
+            return toClone.loadClass(name);
+        }
+
+        // We just ask the wrapper class loader to find the resource for us
+        URL res = toClone.getResource(name.replace('.', '/') + ".class");
+
+        if (res == null) {
+            throw new ClassNotFoundException(name);
+        }
+
+        try {
+            InputStream is = res.openStream();
+            byte[] code = readStreamIntoBuffer(is, 8192);
+            is.close();
+            return defineClass(name, code, 0, code.length);
+        } catch (IOException e) {
+            throw new ClassNotFoundException(name, e);
+        }
+    }
+
+    /**
+     * Reads all data of a stream into a byte array. The method allocates as
+     * much memory as necessary to put the whole data into that byte
+     * array. The data is read in chunks of <code>chunkSize</code>
+     * chunks.<br><br>
+     * <b>Implementation Note: </b> The data is read in chunks of
+     * <code>chunkSize</code> bytes. The data is copied to the result
+     * array. The memory consumption at the end of the reading is
+     * <code>2 x [size of resulting array] + chunkSize</code>.
+     *
+     * @param is the stream to read the data from
+     * @param chunkSize the size of the chunks the data should be read in
+     * @return the <b>whole</b> data of the stream read into an byte array
+     * @throws IllegalArgumentException if chunkSize <= 0
+     * @throws NullPointerException if is == null
+     * @throws IOException thrown if the provided stream encounters IO problems
+     */
+    public static byte[] readStreamIntoBuffer(InputStream is, int chunkSize)
+            throws IOException {
+
+        // Check preconditions.
+        if (chunkSize <= 0) {
+            throw new IllegalArgumentException("chunkSize <= 0");
+        }
+        else if (is == null) {
+            throw new NullPointerException("is is null");
+        }
+
+        // Temporary buffer for read operations and result buffer.
+        byte[] tempBuffer = new byte[chunkSize];
+        byte[] buffer     = new byte[0];
+
+        int bytesRead = 0;  // bytes actual read
+        int oldSize   = 0;  // size of the resulting buffer
+
+        while ((bytesRead = is.read(tempBuffer)) > 0) {
+
+            // Temporary reference to the buffer for the copy operation.
+            byte[] oldBuffer = buffer;
+
+            // Create a new buffer with the size needed and copy data.
+            buffer = new byte[oldSize + bytesRead];
+            System.arraycopy(oldBuffer,  0, buffer, 0,       oldBuffer.length);
+
+            // Copy the new data.
+            System.arraycopy(tempBuffer, 0, buffer, oldSize, bytesRead);
+            oldSize += bytesRead;
+        }
+
+        return buffer;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/exceptionMsgs/IllegalAccessError/IllegalAccessErrorTest.java	Wed Jun 27 09:52:23 2018 +0200
@@ -0,0 +1,405 @@
+/*
+ * 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
+ * @summary Test messages of IllegalAccessError.
+ * @modules java.base/java.lang:open
+ *          java.base/jdk.internal.org.objectweb.asm
+ * @compile IAE_Loader1.java IAE_Loader2.java IAE78_A.java IAE78_B.java
+ *          IllegalAccessErrorTest.java
+ * @run main/othervm -Xbootclasspath/a:. test.IllegalAccessErrorTest
+ */
+
+// Put this test into a package so we see qualified class names in
+// the error messages. Verify that classes are printed with '.' instead
+// of '/'.
+package test;
+
+import java.lang.reflect.*;
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandles.*;
+import static java.lang.invoke.MethodHandles.Lookup.*;
+import java.security.*;
+
+import jdk.internal.org.objectweb.asm.ClassWriter;
+import jdk.internal.org.objectweb.asm.MethodVisitor;
+import static jdk.internal.org.objectweb.asm.Opcodes.*;
+
+import test.*;
+
+abstract public class IllegalAccessErrorTest {
+
+    // interface
+    private static String expectedErrorMessage1a_1 =
+        "class test.IAE1_B cannot access its superinterface test.IAE1_A " +
+        "(test.IAE1_B is in unnamed module of loader test.IAE_Loader1 @";
+    private static String expectedErrorMessage1a_2 =
+        "; test.IAE1_A is in unnamed module of loader 'app')";
+    private static String expectedErrorMessage1b_1 =
+        "class test.IAE1_B cannot access its superinterface test.IAE1_A " +
+        "(test.IAE1_B is in unnamed module of loader 'someCLName1' @";
+    private static String expectedErrorMessage1b_2 =
+        "; test.IAE1_A is in unnamed module of loader 'app')";
+
+    // abstract class
+    private static String expectedErrorMessage2_1 =
+        "class test.IAE2_B cannot access its abstract superclass test.IAE2_A " +
+        "(test.IAE2_B is in unnamed module of loader 'someCLName2' @";
+    private static String expectedErrorMessage2_2 =
+        "; test.IAE2_A is in unnamed module of loader 'app')";
+
+    // class
+    private static String expectedErrorMessage3_1 =
+        "class test.IAE3_B cannot access its superclass test.IAE3_A " +
+        "(test.IAE3_B is in unnamed module of loader 'someCLName3' @";
+    private static String expectedErrorMessage3_2 =
+        "; test.IAE3_A is in unnamed module of loader 'app')";
+
+    public static void test123(String loaderName,
+                               String expectedErrorMessage_1,
+                               String expectedErrorMessage_2,
+                               String testClass) throws Exception {
+        String[] classNames = { testClass };
+        // Some classes under a new Loader.
+        ClassLoader l = new IAE_Loader1(loaderName, classNames);
+
+        try {
+            l.loadClass(testClass);
+            throw new RuntimeException("Expected IllegalAccessError was not thrown.");
+        } catch (IllegalAccessError iae) {
+            String errorMsg = iae.getMessage();
+            if (!(errorMsg.contains(expectedErrorMessage_1) &&
+                  errorMsg.contains(expectedErrorMessage_2))) {
+                System.out.println("Expected: " + expectedErrorMessage_1 + "@id " + expectedErrorMessage_2 +"\n" +
+                                   "but got:  " + errorMsg);
+                throw new RuntimeException("Wrong error message of IllegalAccessError.");
+            } else {
+                System.out.println("Passed with message: " + errorMsg);
+            }
+        }
+    }
+
+    // Generate a class file with the given class name. The class implements Runnable
+    // with a run method to invokestatic the given targetClass/targetMethod.
+    static byte[] iae4_generateRunner(String className,
+                                      String targetClass,
+                                      String targetMethod) throws Exception {
+
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
+                                         + ClassWriter.COMPUTE_FRAMES);
+        cw.visit(V9,
+                ACC_PUBLIC + ACC_SUPER,
+                className.replace(".", "/"),
+                null,
+                "java/lang/Object",
+                new String[] { "java/lang/Runnable" });
+
+        // <init>
+        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+        mv.visitInsn(RETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+
+        // run()
+        String tc = targetClass.replace(".", "/");
+        mv = cw.visitMethod(ACC_PUBLIC, "run", "()V", null, null);
+        mv.visitMethodInsn(INVOKESTATIC, tc, targetMethod, "()V", false);
+        mv.visitInsn(RETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+
+        cw.visitEnd();
+        return cw.toByteArray();
+    }
+
+    // Private method that should raise IllegalAccessError when called.
+    private static void iae4_m() { }
+
+    private static String expectedErrorMessage4 =
+        "class test.Runner4 tried to access private method test.IllegalAccessErrorTest.iae4_m()V " +
+        "(test.Runner4 and test.IllegalAccessErrorTest are in unnamed module of loader 'app')";
+
+    // Test according to java/lang/invoke/DefineClassTest.java
+    public static void test4_privateMethod() throws Exception {
+        final String THIS_PACKAGE = IllegalAccessErrorTest.class.getPackageName();
+        final String THIS_CLASS   = IllegalAccessErrorTest.class.getName();
+        final String CLASS_NAME   = THIS_PACKAGE + ".Runner4";
+        Lookup lookup = lookup();
+
+        // private
+        byte[] classBytes = iae4_generateRunner(CLASS_NAME, THIS_CLASS, "iae4_m");
+        Class<?> clazz = lookup.defineClass(classBytes);
+        Runnable r = (Runnable) clazz.getDeclaredConstructor().newInstance();
+        try {
+            r.run();
+            throw new RuntimeException("Expected IllegalAccessError was not thrown.");
+        } catch (IllegalAccessError exc) {
+            String errorMsg = exc.getMessage();
+            if (!errorMsg.equals(expectedErrorMessage4)) {
+                System.out.println("Expected: " + expectedErrorMessage4 + "\n" +
+                                   "but got:  " + errorMsg);
+                throw new RuntimeException("Wrong error message of IllegalAccessError.");
+            }
+            System.out.println("Passed with message: " + errorMsg);
+        }
+    }
+
+    // Generate a class file with the given class name. The class implements Runnable
+    // with a run method to invokestatic the given targetClass/targetField.
+    static byte[] iae5_generateRunner(String className,
+                                      String targetClass,
+                                      String targetField) throws Exception {
+
+        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS
+                                         + ClassWriter.COMPUTE_FRAMES);
+        cw.visit(V9,
+                 ACC_PUBLIC + ACC_SUPER,
+                 className.replace(".", "/"),
+                 null,
+                 "java/lang/Object",
+                 new String[] { "java/lang/Runnable" });
+
+        // <init>
+        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+        mv.visitVarInsn(ALOAD, 0);
+        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+        mv.visitInsn(RETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+
+        // run()
+        String tc = targetClass.replace(".", "/");
+        mv = cw.visitMethod(ACC_PUBLIC, "run", "()V", null, null);
+        mv.visitFieldInsn(GETSTATIC, tc, targetField, "I");
+        mv.visitInsn(RETURN);
+        mv.visitMaxs(0, 0);
+        mv.visitEnd();
+
+        cw.visitEnd();
+        return cw.toByteArray();
+    }
+
+    // Private field that should raise IllegalAccessError when accessed.
+    private static int iae5_f = 77;
+
+    private static String expectedErrorMessage5 =
+        "class test.Runner5 tried to access private field test.IllegalAccessErrorTest.iae5_f " +
+        "(test.Runner5 and test.IllegalAccessErrorTest are in unnamed module of loader 'app')";
+
+    // Test according to java/lang/invoke/DefineClassTest.java
+    public static void test5_privateField() throws Exception {
+        final String THIS_PACKAGE = IllegalAccessErrorTest.class.getPackageName();
+        final String THIS_CLASS   = IllegalAccessErrorTest.class.getName();
+        final String CLASS_NAME   = THIS_PACKAGE + ".Runner5";
+        Lookup lookup = lookup();
+
+        // private
+        byte[] classBytes = iae5_generateRunner(CLASS_NAME, THIS_CLASS, "iae5_f");
+        Class<?> clazz = lookup.defineClass(classBytes);
+        Runnable r = (Runnable) clazz.getDeclaredConstructor().newInstance();
+        try {
+            r.run();
+            throw new RuntimeException("Expected IllegalAccessError was not thrown.");
+        } catch (IllegalAccessError exc) {
+            String errorMsg = exc.getMessage();
+            if (!errorMsg.equals(expectedErrorMessage5)) {
+                System.out.println("Expected: " + expectedErrorMessage5 + "\n" +
+                                   "but got:  " + errorMsg);
+                throw new RuntimeException("Wrong error message of IllegalAccessError.");
+            }
+            System.out.println("Passed with message: " + errorMsg);
+        }
+    }
+
+    private static String expectedErrorMessage6 =
+        "failed to access class test.IAE6_A from class test.IAE6_B " +
+        "(test.IAE6_A is in unnamed module of loader 'app'; test.IAE6_B is in unnamed module of loader 'test6_class_CL' @";
+
+    public static void test6_class() throws Exception {
+        ClassLoader base = IllegalAccessErrorTest.class.getClassLoader();
+        IAE_Loader2 loader = new IAE_Loader2("test6_class_CL", base.getParent(), base, new String[0],
+                new String[] { IAE6_A.class.getName() });
+        Class<?> cl = loader.loadClass(IAE6_B.class.getName());
+        Method m = cl.getDeclaredMethod("create", new Class[0]);
+        m.setAccessible(true);
+
+        try {
+            m.invoke(null, new Object[0]);
+            throw new RuntimeException("Expected IllegalAccessError was not thrown.");
+        } catch (InvocationTargetException e) {
+            IllegalAccessError iae = (IllegalAccessError) e.getCause();
+            String errorMsg = iae.getMessage();
+            if (!errorMsg.contains(expectedErrorMessage6)) {
+                System.out.println("Expected: " + expectedErrorMessage6 + "id)\n" +
+                                   "but got:  " + errorMsg);
+                throw new RuntimeException("Wrong error message of IllegalAccessError.");
+            }
+            System.out.println("Passed with message: " + errorMsg);
+        }
+    }
+
+    private static String expectedErrorMessage7_1 =
+        "class test.IAE78_B tried to access method test.IAE78_A.<init>()V " +
+        "(test.IAE78_B is in unnamed module of loader 'test7_method_CL' @";
+    private static String expectedErrorMessage7_2 =
+        "; test.IAE78_A is in unnamed module of loader 'app')";
+
+    // Similar to test4.
+    public static void test7_method() throws Exception {
+        ClassLoader base = IllegalAccessErrorTest.class.getClassLoader();
+        IAE_Loader2 loader = new IAE_Loader2("test7_method_CL", base.getParent(), base, new String[0],
+                new String[] {IAE78_A.class.getName()});
+        Class<?> cl = loader.loadClass(IAE78_B.class.getName());
+        Method m = cl.getDeclaredMethod("create", new Class[0]);
+
+        try {
+            m.invoke(null, new Object[0]);
+        } catch (InvocationTargetException e) {
+            IllegalAccessError iae = (IllegalAccessError) e.getCause();
+            String errorMsg = iae.getMessage();
+            if (!(errorMsg.contains(expectedErrorMessage7_1) &&
+                  errorMsg.contains(expectedErrorMessage7_2))) {
+                System.out.println("Expected: " + expectedErrorMessage7_1 + "id" + expectedErrorMessage7_2 + "\n" +
+                                   "but got:  " + errorMsg);
+                throw new RuntimeException("Wrong error message of IllegalAccessError.");
+            }
+            System.out.println("Passed with message: " + errorMsg);
+        }
+    }
+
+    private static String expectedErrorMessage8_1 =
+        "class test.IAE78_B tried to access field test.IAE78_A.f " +
+        "(test.IAE78_B is in unnamed module of loader 'test8_field_CL' @";
+    private static String expectedErrorMessage8_2 =
+        "; test.IAE78_A is in unnamed module of loader 'app')";
+
+    // Similar to test5.
+    public static void test8_field() throws Exception {
+        ClassLoader base = IllegalAccessErrorTest.class.getClassLoader();
+        IAE_Loader2 loader = new IAE_Loader2("test8_field_CL", base.getParent(), base, new String[0],
+                                             new String[] { IAE78_A.class.getName() });
+        Class<?> cl = loader.loadClass(IAE78_B.class.getName());
+        Method m = cl.getDeclaredMethod("access", new Class[0]);
+
+        try {
+            m.invoke(null, new Object[0]);
+        }
+        catch (InvocationTargetException e) {
+            IllegalAccessError iae = (IllegalAccessError) e.getCause();
+            String errorMsg = iae.getMessage();
+            if (!(errorMsg.contains(expectedErrorMessage8_1) &&
+                  errorMsg.contains(expectedErrorMessage8_2))) {
+                System.out.println("Expected: " + expectedErrorMessage8_1 + "id" + expectedErrorMessage8_2 + "\n" +
+                                   "but got:  " + errorMsg);
+                throw new RuntimeException("Wrong error message of IllegalAccessError.");
+            }
+            System.out.println("Passed with message: " + errorMsg);
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        test123(null,          expectedErrorMessage1a_1, expectedErrorMessage1a_2, "test.IAE1_B"); // interface
+        test123("someCLName1", expectedErrorMessage1b_1, expectedErrorMessage1b_2, "test.IAE1_B"); // interface
+        test123("someCLName2", expectedErrorMessage2_1,  expectedErrorMessage2_2,  "test.IAE2_B"); // abstract class
+        test123("someCLName3", expectedErrorMessage3_1,  expectedErrorMessage3_2,  "test.IAE3_B"); // class
+        test4_privateMethod();
+        test5_privateField();
+        test6_class();
+        test7_method();
+        test8_field();
+    }
+}
+
+// Class hierarchies for test1.
+interface IAE1_A {
+    public IAE1_D gen();
+}
+
+class IAE1_B implements IAE1_A {
+    public IAE1_D gen() {
+        return null;
+    }
+}
+
+abstract class IAE1_C {
+}
+
+class IAE1_D extends IAE1_C {
+}
+
+
+// Class hierarchies for test2.
+abstract class IAE2_A {
+    abstract public IAE2_D gen();
+}
+
+class IAE2_B extends IAE2_A {
+    public IAE2_D gen() {
+        return null;
+    }
+}
+
+abstract class IAE2_C {
+}
+
+class IAE2_D extends IAE2_C {
+}
+
+
+// Class hierarchies for test3.
+class IAE3_A {
+    public IAE3_D gen() {
+        return null;
+    };
+}
+
+class IAE3_B extends IAE3_A {
+    public IAE3_D gen() {
+        return null;
+    }
+}
+
+abstract class IAE3_C {
+}
+
+class IAE3_D extends IAE3_C {
+}
+
+
+// Class hierarchies for test6.
+class IAE6_A {
+    IAE6_A() {
+        // Nothing to do.
+    }
+}
+
+class IAE6_B {
+    public static void create() {
+        new IAE6_A();
+    }
+}
--- a/test/hotspot/jtreg/runtime/modules/AccessCheck/ExpQualToM1PrivateMethodIAE.java	Wed Jun 27 12:46:15 2018 +0200
+++ b/test/hotspot/jtreg/runtime/modules/AccessCheck/ExpQualToM1PrivateMethodIAE.java	Wed Jun 27 09:52:23 2018 +0200
@@ -103,9 +103,10 @@
             String message = e.getMessage();
             System.out.println(e.toString());
             // java.lang.IllegalAccessError:
-            //   tried to access method p2.c2.method2()V from class p1.c1 (p2.c2 is in module m2x of loader
+            //   tried to access private method p2.c2.method2()V from class p1.c1 (p2.c2 is in module m2x of loader
             //   myloaders.MySameClassLoader @<id>; p1.c1 is in module m1x of loader myloaders.MySameClassLoader @<id>)
-            if (!message.contains("class p1.c1 tried to access method p2.c2.method2()V (p1.c1 is in module m1x of loader myloaders.MySameClassLoader @") ||
+            if (!message.contains("class p1.c1 tried to access private method p2.c2.method2()V " +
+                                  "(p1.c1 is in module m1x of loader myloaders.MySameClassLoader @") ||
                 !message.contains("; p2.c2 is in module m2x of loader myloaders.MySameClassLoader @")) {
               throw new RuntimeException("Test Failed, an IAE was thrown with the wrong message: " + e.toString());
             }