-
Bug
-
Resolution: Fixed
-
P4
-
9, 11
-
b14
-
x86_64
-
linux
-
Verified
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8203526 | 11.0.1 | Mandy Chung | P4 | Resolved | Fixed | team |
A DESCRIPTION OF THE PROBLEM :
When using reflection API there are security checks to the callers (unless .setAccessible(true) is called before),
those checks are cached in `Executable::securityCheckCache` field, and that field is pointing to the caller class (and its class loader).
The problem occurs when the method is first invoked, and at that a JNI accessor is created (`NativeMethodAccessorImpl`).
The bug is that instead of passing the root method, the code is passing the child method, which could contain such `securityCheckCache` cache.
Before JDK 9 this bug was happening only for protected method and constructors, because there was a quick path to avoid security cache (`Reflection.quickCheckMemberAccess`) which was removed in JDK 9.
Since JDK 9 it is happening for all variations. The following code `Thread.class.getMethod("currentThread").invoke(null)` will cause the caller to leak.
For methods and constructors the path to root GC is kept as long as `NativeMethodAccessorImpl` (or `NativeConstructorAccessorImpl`) is kept,
which is gone after inflationThreshold (15) calls to the method (or constuctor).
Afterwards the accessor is turned into bytecode, and no longer holds reference to Java objects.
But for fields the leak will stay forever, and will always leak the first caller, if that caller required security check.
The fix is passing the parent to the accessor, since it contains the same information required, but won't cause any leaks for caller classes.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
I've attached patch which adds a unit-test and fixes the problem.
CUSTOMER SUBMITTED WORKAROUND :
A workaround to bypass the bug is to make sure to invoke the method which will be used in future class loaders before they use it. Because then the accessor is pointing to the app class loader, and there can't be any leak.
This workaround is very targeted, and you must know which methods are being used in your application server.
If you have a memory dump, you can use Eclipse Memory Analyzer to run the following OQL script to find those methods:
SELECT * FROM jdk.internal.reflect.NativeMethodAccessorImpl s WHERE
((s.method.securityCheckCache != null) and
(s.method.root.methodAccessor.delegate = s) and
(s.method.securityCheckCaches.@clazz.@classLoaderId != s.method.clazz.@classLoaderId))
FREQUENCY : always
When using reflection API there are security checks to the callers (unless .setAccessible(true) is called before),
those checks are cached in `Executable::securityCheckCache` field, and that field is pointing to the caller class (and its class loader).
The problem occurs when the method is first invoked, and at that a JNI accessor is created (`NativeMethodAccessorImpl`).
The bug is that instead of passing the root method, the code is passing the child method, which could contain such `securityCheckCache` cache.
Before JDK 9 this bug was happening only for protected method and constructors, because there was a quick path to avoid security cache (`Reflection.quickCheckMemberAccess`) which was removed in JDK 9.
Since JDK 9 it is happening for all variations. The following code `Thread.class.getMethod("currentThread").invoke(null)` will cause the caller to leak.
For methods and constructors the path to root GC is kept as long as `NativeMethodAccessorImpl` (or `NativeConstructorAccessorImpl`) is kept,
which is gone after inflationThreshold (15) calls to the method (or constuctor).
Afterwards the accessor is turned into bytecode, and no longer holds reference to Java objects.
But for fields the leak will stay forever, and will always leak the first caller, if that caller required security check.
The fix is passing the parent to the accessor, since it contains the same information required, but won't cause any leaks for caller classes.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
I've attached patch which adds a unit-test and fixes the problem.
CUSTOMER SUBMITTED WORKAROUND :
A workaround to bypass the bug is to make sure to invoke the method which will be used in future class loaders before they use it. Because then the accessor is pointing to the app class loader, and there can't be any leak.
This workaround is very targeted, and you must know which methods are being used in your application server.
If you have a memory dump, you can use Eclipse Memory Analyzer to run the following OQL script to find those methods:
SELECT * FROM jdk.internal.reflect.NativeMethodAccessorImpl s WHERE
((s.method.securityCheckCache != null) and
(s.method.root.methodAccessor.delegate = s) and
(s.method.securityCheckCaches.@clazz.@classLoaderId != s.method.clazz.@classLoaderId))
FREQUENCY : always
- backported by
-
JDK-8203526 Reflection API is causing caller classes to leak
-
- Resolved
-
- relates to
-
JDK-8202608 CommonSeeder test needs a white-box testing mechanism to replace the default entropy source
-
- Closed
-
-
JDK-8206240 java.lang.Class.newInstance() is causing caller to leak
-
- Resolved
-
-
JDK-8206208 Class::newInstance leaks the caller Class
-
- Closed
-