JDK-8280902 : ResourceBundle::getBundle may throw NPE when invoked by JNI code with no caller frame
  • Type: Sub-task
  • Component: core-libs
  • Sub-Component: java.util:i18n
  • Affected Version: 9
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2022-01-28
  • Updated: 2022-03-09
  • Resolved: 2022-03-09
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 19
19 masterFixed
Related Reports
CSR :  
Description
Need to specify the behavior of ResourceBundle::getBundle when invoked by JNI code with no caller frame and what module/class loader is the default (for the getBundle APIs without the module/class loader parameter).

The unnamed module defined by the system class loader may be an appropriate default to consider.

ResourceBundle::clearCache also needs to be looked at.
Comments
Changeset: 31ad80a2 Author: Tim Prinzing <tim.prinzing@oracle.com> Committer: Mandy Chung <mchung@openjdk.org> Date: 2022-03-09 04:02:17 +0000 URL: https://git.openjdk.java.net/jdk/commit/31ad80a229e3f67823ff8f1fc914c5503f184b57
09-03-2022

A pull request was submitted for review. URL: https://git.openjdk.java.net/jdk/pull/7663 Date: 2022-03-02 18:56:40 +0000
02-03-2022

Changed to use the unnamed module defined to the system class loader and created a pull request: https://github.com/openjdk/jdk/pull/7663
02-03-2022

I think you want to use the unnamed module defined to the system class loader instead of the unnamed module defined to the boot loader: ClassLoader.getSystemClassLoader().getUnnamedModule()
02-03-2022

Also added the following Javadoc to the associated caller sensitive methods: * In cases where this method is called from a context where * there is no caller frame on the stack (e.g. when called directly * from a JNI attached thread), the callers module will be considered * to be the bootloader unnamed module {@link BootLoader#getUnnamedModule}.
02-03-2022

The caller class returned by Reflection::getCallerClass was used to gain access to it's module in most cases and class loader in one case. I added a method to translate the caller class to caller module so that the decision of what module represents the caller with no stack frame is made in a single place. The following method was added (which might be a little strict as it uses the boot loader unnamed module): /** * Determine the module to be used for the caller. If * {@link Reflection#getCallerClass()} is called from JNI with an empty * stack frame the caller will be null, so the bootloader unnamed module * will be used. * @param caller * @return */ private static Module getCallerModule(Class<?> caller) { final Module callerModule = (caller != null) ? caller.getModule() : BootLoader.getUnnamedModule(); return callerModule; } Calls made to caller.getModule() were replaced with getCallerModule(caller) The one place a class loader was produced from the caller in getBundleImpl it was rewritten to route through the getCallerModule method: final ClassLoader loader = (caller != null) ? caller.getClassLoader() : getLoader(getCallerModule(caller)); A JNI test was added which calls getBundle to fetch a test bundle from a location added to the boot classpath, fetches a string out of the bundle and verifies it, and calls clearCache.
02-03-2022