Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8202113

Reflection API is causing caller classes to leak

    Details

    • Subcomponent:
    • Resolved In Build:
      b14
    • CPU:
      x86_64
    • OS:
      linux
    • Verification:
      Verified

      Backports

        Description

        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


          Attachments

            Issue Links

              Activity

                People

                • Assignee:
                  mchung Mandy Chung
                  Reporter:
                  webbuggrp Webbug Group
                • Votes:
                  0 Vote for this issue
                  Watchers:
                  4 Start watching this issue

                  Dates

                  • Created:
                    Updated:
                    Resolved: