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

java.lang.Class.newInstance() is causing caller to leak

XMLWordPrintable

      A DESCRIPTION OF THE PROBLEM :
      This is a similar bug to: https://bugs.openjdk.java.net/browse/JDK-8202113
      Which I've reported, and I'm sorry to report we've missed one case which needs to be fixed also

      Only now its with the Class.newInstance() method which caches the caller classloader in Class.newInstanceCallerCache variable

      I would suggest to make that cache WeakReference so it could be freed if needed.
      Since the WeakReference is to caller Class, then it won't be collected as long as the caller class ClassLoader isn't collected, so its safe to say the weak reference will stay as long as the caller ClassLoader has a path to GC.

      Something like this in ./src/java.base/share/classes/java/lang/Class.java newInstance() method:

              WeakReference<Class<?>> cachedCallerRef = newInstanceCallerCache;
              Class<?> cachedCaller = cachedCallerRef != null ? cachedCallerRef.get() : null;
              if (cachedCaller != caller) {
                  int modifiers = tmpConstructor.getModifiers();
                  Reflection.ensureMemberAccess(caller, this, this, modifiers);
                  newInstanceCallerCache = new WeakReference<>(caller);
              }

      will do.

      Same as previous bug reported, this bug also exists in Java8 and below, but was almost non-existance because of the `Reflection.quickCheckMemberAccess` which avoided caching the `newInstanceCallerCache`
      But since Java9 that code was removed (revision 9d0388c6b336) it always happens under Java9+

      As for unit-test, it should be added to ReflectionCallerCacheTest.java


      REGRESSION : Last worked in version 8u172

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Call java.lang.String.class.newInstance() under a class loader, and see that it can't freed

      Or, add another case to unit-test in ./test/jdk/java/lang/reflect/callerCache/ReflectionCallerCacheTest.java
      to create an instance directly from the class using newInstance() method which will reproduce the problem.

      Currently there's a test only for calling a newInstance from the Constructor of a Class - AccessTest$PublicConstructor.


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      It would not leak the caller classloader

      CUSTOMER SUBMITTED WORKAROUND :
      None, its not possible to find all classes which were called by a classloader.

      Unless you know especially which class you've called and all your external dependencies.


      FREQUENCY : always


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

              Created:
              Updated:
              Resolved: