JDK-8337622 : IllegalArgumentException in java.lang.reflect.Field.get
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 21.0.5,23
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2024-08-01
  • Updated: 2024-09-16
  • Resolved: 2024-08-12
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 21 JDK 24
21.0.6-oracleFixed 24 b11Fixed
Related Reports
Relates :  
Relates :  
Sub Tasks
JDK-8337956 :  
Description
I am seeing errors like the following testing JDK 23 that do not occur with JDK 22.

```
Caused by: java.lang.IllegalArgumentException: Can not get final java.lang.Class field java.lang.Class.componentType on java.lang.Class
	at java.base/jdk.internal.reflect.MethodHandleFieldAccessorImpl.newGetIllegalArgumentException(MethodHandleFieldAccessorImpl.java:86)
	at java.base/jdk.internal.reflect.MethodHandleObjectFieldAccessorImpl.get(MethodHandleObjectFieldAccessorImpl.java:61)
	at java.base/java.lang.reflect.Field.get(Field.java:444)
```

The symptoms look similar to https://bugs.openjdk.org/browse/JDK-8301663 which was fixed in JDK 20, but testing the repro from that bug shows a regression between JDK 22 and JDK 23:

import java.lang.reflect.Field;
public class C {

    public static void main(String[] args) throws Exception {
        int count = 0;
        for (int i = 0; i < 100_000; ++i) {
            try {
                Field f = Class.class.getDeclaredField("componentType");
                f.setAccessible(true);
                Object val = f.get(Runnable.class);
            } catch (IllegalArgumentException e) {
                count += 1;
            }
        }
        System.out.println(count);
    }
}

java -fullversion
openjdk full version "22.0.2+9-70"
java --add-opens java.base/java.lang=ALL-UNNAMED C
0

java -fullversion
openjdk full version "23-ea+34-2361"
java --add-opens java.base/java.lang=ALL-UNNAMED C
18499
Comments
Why is this not backported to JDK23?
16-09-2024

Why is this not backported to JDK23?
16-09-2024

Critical fix request [21u] I want to backport this to 21.0.5 as we backported JDK-8333542 to this release, too. The test reproduces the error well, so I think it is better to add this late then to go without fixing this. Medium risk as it is a simple change but in a central component. Clean backport. Test passes and fails without the fix. SAP nightly testing passed.
16-09-2024

Yes, this should be backported to JDK 23 also because JDK-8333542 was backported to JDK 23.
16-09-2024

A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk21u/pull/454 Date: 2024-09-14 19:51:14 +0000
14-09-2024

[~coffeys], [~ccheung], shoudn't this go to 23, too?
14-09-2024

Changeset: 41e31d6b Branch: master Author: Coleen Phillimore <coleenp@openjdk.org> Date: 2024-08-12 17:56:46 +0000 URL: https://git.openjdk.org/jdk/commit/41e31d6b0ae00d70b6fb20c89318fde2bc605edb
12-08-2024

ILW = M (test failure/exception not crash) L (Field.get() of this field not likely) L (workaround: don't get this field for non-array types) = P4
07-08-2024

A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk/pull/20498 Date: 2024-08-07 18:32:18 +0000
07-08-2024

> That said, why do we use this field for the init lock? I would (naively?) have expected the init lock to be an oop field in instanceKlass, not a field of the mirror. EDIT: I guess to save space. Yes, back then we cared about the space so we reused this oop field. The fix is to give it its own injected field. It's a field in the mirror and not the InstanceKlass to save having another GC root. Thank you for commenting on this bug. I didn't know if this is something Java programmers do and expect to work. I agree then it shouldn't be a P2. I asked for it to be deferred from fixing in JDK 23, but if we ILW it to MLL then it's a P4. It is a regression though.
07-08-2024

Defer Request: This problem exists in JDK 11 and 17 also, but in JDK 20 caused an IllegalArgumentException because of the new reflection. The bug is a regression because we backed out a fix that also fixed this problem in order to fix JVMTI. The additional fix for this is relatively small, but may have other unintended consequences. The likelihood of someone reflecting on the componentType field for a Class and not an array where it would have a valid value seems small.
06-08-2024

JDK 11 and 17 don't throw IllegalArgumentException although they do print the value of the componentType field as an array, which is the type of the internal lock: java --add-opens java.base/java.lang=ALL-UNNAMED ComponentTypeFieldTest val is [I@27c170f0 0 In JDK 20, from JDK-8301663: > The `componentType` of Runnable.class is an int array and hence ClassCastException was thrown when VarHandle is used to get the field value.
06-08-2024

This is broken in JDK 11 and 17 also. The VM shared the componentType field with an internal class initialization field that it used for locking. I had to put this internal lock back because we need to hold the lock for JVMTI class prepare events. We should release note this for JDK 23. We can backport a simple fix, and fix in JDK 23.01 if it's important enough.
06-08-2024

RT Triage: ILW = HML = P2
06-08-2024

Given the bisect, I suspect this is hotspot related so moving component to "hotspot". Let me know if this is not correct.
01-08-2024

This bisects to the fix for https://bugs.openjdk.org/browse/JDK-8333542 Discussion in https://bugs.openjdk.org/browse/JDK-8333542 mentions https://bugs.openjdk.org/browse/JDK-8288064, which fixed the original report of https://bugs.openjdk.org/browse/JDK-8301663
01-08-2024