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

Reflection API is causing caller classes to leak

    XMLWordPrintable

Details

    • b14
    • x86_64
    • linux
    • 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

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

                Dates

                  Created:
                  Updated:
                  Resolved: