JDK-8205061 : JVMTI GetClassFields/Methods return jfield/methodIDs without class init
  • Type: Bug
  • Component: hotspot
  • Sub-Component: jvmti
  • Affected Version: 11
  • Priority: P3
  • Status: Open
  • Resolution: Unresolved
  • OS: generic
  • CPU: generic
  • Submitted: 2018-06-14
  • Updated: 2025-05-15
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 26
26Unresolved
Related Reports
Relates :  
Description
JVMTI GetClassFields and GetClassMethods calls return
respectively arrays of jfieldIDs and jmethodIDs without triggering
class initialization.

These jfieldIDs and jmethodIDs are shared with JNI.

JNI GetFieldID and GetMethodID trigger class initialization prior to returning the jfieldIDs and jmethodIDs.

jfieldIDs and jmethodIDs can be used by other JNI APIs to access fields and methods. Those other APIS presume that the class has been initialized without checking to help with performance.

When JNI was spec'ed, JVM/TI didn't exist and so the idea of another
API being able to return jfieldIDs or jmethodIDs was not considered.

So these JNI function families have a problem when called with
jfieldIDs or jmethodIDs that were obtained by JVM/TI instead of JNI:

  Get<type>Field Routines
  Set<type>Field Routines
  GetStatic<type>Field Routines
  SetStatic<type>Field Routines
  Call*<type>Method* Routines

All of these JNI functions have an assumption that the associated
class has been initialized because the JNI functions that fetched
the jfieldIDs or jmethodIDs would have made sure of that. So when
we added JVM/TI, we probably should have added a JVM/TI specific
check to make sure that the associated class is initialized.

I don't know if the JNI functions will detect an error if one of
these functions is called on an uninitialized class. Because of
the age of the API, I suspect not. It should be possible to copy
a JVM/TI ClassPrepare event test and modify it to call a JNI
Get<type>Field() or GetStatic<type>Field() function and see what
happens.

The risk is exposing fields and methods of an uninitialized class to JNI.

This requires both a JVMTI specification and the related implementation change.
Comments
Moved to 22.
18-04-2023

Targeting to 17.
04-11-2020

Moving this to next release 16 once more.
08-05-2020

If I understand it correctly the fix can be pretty simple. The JVMTI GetClassMethods/GetClassFields have follow the JNI GetMethodID/GetFieldID and make this call: klass->initialize(CHECK_NULL); But it seems, a spec update is also needed here (and so, filing a CSR). I feel this fix is risky at this stage of development cycle. So that, I'm retargeting it to 14. Will try to fix this issue early in the release cycle. Please, let me know if there are any objections to this.
04-06-2019

There's a significant difference between the VirtualMachine.allClasses() API (which is supposed to return uninitialized classes) and the ability to invoke a method of, or access a field of, an uninitialized class. Certain actions must result in a class being initialized - including access to static fields or invocations of static methods. It is a significant bug if these rules can be circumvented. There are two ways to enforce that in terms of JNI/JVM TI: a) at the time the "method id" or "field id" is handed out; or b) at the time the "method id" or "field id" is used for an invocation or access JNI explicitly specifies that option (a) applies. Given that JVM TI reuses those JNI types: https://docs.oracle.com/javase/9/docs/specs/jvmti.html#jniTypes it would seem implicit that the rules for those types, as specified by JNI, should also apply in JVM TI. In which case it seems a significant bug in JVM TI if it can by-pass option (a) when option (b) is also not in place! JVM TI GetLoadedClasses should also be more explicit about what exactly "loaded" means (as JDI VirtualMachine.allClasses() is), but taken on face value it should include uninitialized classes as they have been loaded!
12-07-2018

JDK-8181144 was filed recently to request the opposite behavior. It wants the JDI VirtualMachine.allClasses() to return uninitialized classes. I assume this translates to the JVMTI GetLoadedClasses() API, and it does not return uniniitialized classes (although I don't see anything in the spec to indicate that is the case).
11-07-2018

I agree with Dan, this has to be a hotspot/jvmti bug and made this update. Also, moved the bug to 12.
19-06-2018

Please consider moving from 'hotspot/svc' -> 'hotspot/jvmti' since I think the "bug" is entirely the "responsibility" of JVM/TI. It might require changes to JNI code (in jni.cpp), but that code will only get called/used if JVM/TI APIs are in use.
14-06-2018