Problem description:
When running code on Oracle 1.8 (currently u471), and when the code is compiled using the
JDK 21 compiler using the --release 8 (or source/target compatibility to 1.8), when code tries to
access the parameter names of a synthetic inner class method via reflection, this fails with a MalformedParametersException.
Analysis
-
The issue arises when classes are compiled with JDK 21 or later, previous JDK works. The change is likely related to this issue: https://bugs.openjdk.org/browse/JDK-8292275
-
The issue is specific to Oracle JDK 1.8, other OpenJDK 1.8 distributions not show the problem.
-
The problem appears to be related to how the JVM gets parameter names via reflection.
-
Similar JDK bugs have been reported, and reported as fixed
- https://bugs.openjdk.org/browse/JDK-8058322: The issue on 8, 9, apparently fixed on OpenJDK (Reported on 2014-09-12, on Fixed 2014-11-10 in JDK9, 2024-10-08 in JDK8)
- https://bugs.openjdk.org/browse/JDK-8341145: Duplicates JDK-8058322, but reported as a bug on 21, 23, 24 (Reported on 2024-09-27, Fixed via backport in JDK-8058322 on 2024-10-08)
- https://bugs.openjdk.org/browse/JDK-8170063: Duplicates JDK-8058322 (Reported on 2016-11-11)
-
JDK 21 compiler and later adds the following to the inner class synthetic method
// access flags 0x1041 public synthetic bridge accept(Ljava/lang/Object;)V + // parameter final synthetic <no name> L0 LINENUMBER 11 L0 ALOAD 0 ALOAD 1 CHECKCAST java/lang/Runnable INVOKEVIRTUAL io/github/bric3/MalformedReproducer$RunnerRunner.accept (Ljava/lang/Runnable;)V RETURN L1 LOCALVARIABLE this Lio/github/bric3/MalformedReproducer$RunnerRunner; L0 L1 0 MAXSTACK = 2 MAXLOCALS = 2ASM's equivalent code:
methodVisitor.visitParameter(null, ACC_FINAL | ACC_SYNTHETIC); -
Workaround: pass the compiler the
-parameters
Minimal reproducer:
The problem mostly manifested via ByteBuddy, for example via the redefine method.
This test method show the issue ShouldNotRaiseMalformedParametersExTest.with_bb_redefine
A more precise reproducer is Reproducer.DefaultRunnableConsumer.class.getDeclaredMethod("accept", Object.class).getParameters();.
java.lang.reflect.MalformedParametersException: Invalid parameter name ""
at java.lang.reflect.Executable.verifyParameters(Executable.java:386)
at java.lang.reflect.Executable.privateGetParameters(Executable.java:416)
at java.lang.reflect.Executable.getParameters(Executable.java:357)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at net.bytebuddy.utility.Invoker$Dispatcher.invoke(Unknown Source)
at net.bytebuddy.utility.dispatcher.JavaDispatcher$Dispatcher$ForNonStaticMethod.invoke(JavaDispatcher.java:1049)
at net.bytebuddy.utility.dispatcher.JavaDispatcher$ProxiedInvocationHandler.invoke(JavaDispatcher.java:1179)
at net.bytebuddy.description.method.$Proxy21.getParameters(Unknown Source)
at net.bytebuddy.description.method.ParameterDescription$ForLoadedParameter.isNamed(ParameterDescription.java:296)
at net.bytebuddy.description.method.ParameterDescription$AbstractBase.asToken(ParameterDescription.java:188)
at net.bytebuddy.description.method.ParameterDescription$AbstractBase.asToken(ParameterDescription.java:135)
at net.bytebuddy.description.method.ParameterList$AbstractBase.asTokenList(ParameterList.java:99)
at net.bytebuddy.description.method.MethodDescription$AbstractBase.asToken(MethodDescription.java:909)
at net.bytebuddy.description.method.MethodDescription$AbstractBase.asToken(MethodDescription.java:461)
at net.bytebuddy.description.method.MethodList$AbstractBase.asTokenList(MethodList.java:90)
at net.bytebuddy.dynamic.scaffold.InstrumentedType$Factory$Default$1.represent(InstrumentedType.java:467)
at net.bytebuddy.ByteBuddy.redefine(ByteBuddy.java:1001)
at net.bytebuddy.ByteBuddy.redefine(ByteBuddy.java:976)
at net.bytebuddy.ByteBuddy.redefine(ByteBuddy.java:954)
at ShouldNotRaiseMalformedParametersExTest.with_bb_redefine(ShouldNotRaiseMalformedParametersExTest.java:25)
at java.lang.reflect.Method.invoke(Method.java:498)
at java.util.ArrayList.forEach(ArrayList.java:1259)
at java.util.ArrayList.forEach(ArrayList.java:1259)