-
Type:
Bug
-
Resolution: Unresolved
-
Priority:
P4
-
None
-
Affects Version/s: 8, 17
-
Component/s: core-libs
-
generic
ADDITIONAL SYSTEM INFORMATION :
Software:
System Software Overview:
System Version: Ubuntu 22.04.4 LTS
A DESCRIPTION OF THE PROBLEM :
A java.lang.IllegalAccessError occurs in HotSpot during reflection inflation (when switching from NativeMethodAccessorImpl to GeneratedMethodAccessor) when the target class is loaded by a custom ClassLoader.
The error appears after the reflection call is executed multiple times (exceeding the inflation threshold, typically 15). The JVM attempts to define a generated accessor class (sun.reflect.GeneratedMethodAccessor) to optimize the call. However, this generated class fails with an IllegalAccessError, likely because the internal reflection mechanism cannot properly access or link against the necessary classes when the call originates from a class loaded by a non-delegating custom ClassLoader.
OpenJ9 does not exhibit this behavior and handles the reflection inflation correctly.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Compile the provided Test.java.
2. Run with java -Xcomp Test.
---------- BEGIN SOURCE ----------
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
public class Test {
public static void targetMethod(float f, int i) {}
public static void loopMethod(int param) {
int i = -13;
while ((++i) < 302) {
try {
Method m = Test.class.getMethod("targetMethod", float.class, int.class);
m.invoke(null, 0, param);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
public static void main(String[] args) {
try {
ClassLoader cl = new CustomLoader();
Class<?> cls = cl.loadClass("Test");
Method m = cls.getMethod("loopMethod", int.class);
m.invoke(null, 1);
} catch (Exception ex) {
ex.printStackTrace();
}
}
static class CustomLoader extends ClassLoader {
public Class loadClass(String name) throws ClassNotFoundException {
if (!name.startsWith("java.") && name.startsWith("")) {
try {
String path = "/" + name.replace('.', '/') + ".class";
InputStream is = getClass().getResourceAsStream(path);
if (is == null) return super.loadClass(name);
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
byte[] data = new byte[1024];
int nRead;
while ((nRead = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
byte[] b = buffer.toByteArray();
return defineClass(name, b, 0, b.length);
} catch (Exception e) {
throw new ClassNotFoundException(name, e);
}
}
return super.loadClass(name);
}
}
}
---------- END SOURCE ----------
FREQUENCY :
ALWAYS
Software:
System Software Overview:
System Version: Ubuntu 22.04.4 LTS
A DESCRIPTION OF THE PROBLEM :
A java.lang.IllegalAccessError occurs in HotSpot during reflection inflation (when switching from NativeMethodAccessorImpl to GeneratedMethodAccessor) when the target class is loaded by a custom ClassLoader.
The error appears after the reflection call is executed multiple times (exceeding the inflation threshold, typically 15). The JVM attempts to define a generated accessor class (sun.reflect.GeneratedMethodAccessor) to optimize the call. However, this generated class fails with an IllegalAccessError, likely because the internal reflection mechanism cannot properly access or link against the necessary classes when the call originates from a class loaded by a non-delegating custom ClassLoader.
OpenJ9 does not exhibit this behavior and handles the reflection inflation correctly.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Compile the provided Test.java.
2. Run with java -Xcomp Test.
---------- BEGIN SOURCE ----------
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
public class Test {
public static void targetMethod(float f, int i) {}
public static void loopMethod(int param) {
int i = -13;
while ((++i) < 302) {
try {
Method m = Test.class.getMethod("targetMethod", float.class, int.class);
m.invoke(null, 0, param);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
public static void main(String[] args) {
try {
ClassLoader cl = new CustomLoader();
Class<?> cls = cl.loadClass("Test");
Method m = cls.getMethod("loopMethod", int.class);
m.invoke(null, 1);
} catch (Exception ex) {
ex.printStackTrace();
}
}
static class CustomLoader extends ClassLoader {
public Class loadClass(String name) throws ClassNotFoundException {
if (!name.startsWith("java.") && name.startsWith("")) {
try {
String path = "/" + name.replace('.', '/') + ".class";
InputStream is = getClass().getResourceAsStream(path);
if (is == null) return super.loadClass(name);
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
byte[] data = new byte[1024];
int nRead;
while ((nRead = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
byte[] b = buffer.toByteArray();
return defineClass(name, b, 0, b.length);
} catch (Exception e) {
throw new ClassNotFoundException(name, e);
}
}
return super.loadClass(name);
}
}
}
---------- END SOURCE ----------
FREQUENCY :
ALWAYS
- relates to
-
JDK-8013527 calling MethodHandles.lookup on itself leads to errors
-
- Resolved
-