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

RI does not follow the JVMTI RedefineClasses spec that is too strict in the definition

XMLWordPrintable

    • 9
    • b18
    • generic
    • generic
    • Verified

      There is a discrepancy between the behaviour of Java 9 and the jvmti
      spec (http://cr.openjdk.java.net/~mr/jigsaw/spec/jvmti.html#RedefineClasses)

      The spec states:

      "The redefinition may change method bodies, the constant pool and attributes.
      The redefinition must not add, remove or rename fields or methods, change the signatures of methods, change modifiers, or change inheritance."

      However, RI allows private methods and inner classes to be added without throwing
      JVMTI_ERROR_UNSUPPORTED_REDEFINITION_METHOD_ADDED.

      There is the transform method:

              @Override
              public byte[] transform(Module module, ClassLoader loader, String className, Class<?> classBeingRedefined,
                      ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
                  if (className.equals("p/C")) {
                      transformModule(module);
                      byte[] retransformedClazz1Bytes = new LocalDirClassLoader("Instrumentation.redefine_after", null).loadClassData("p/C.class");
                  } else {
                      return null;
                  }
              }

      that substitutes the class p/C
      ----------------------------------------------------------------
      package p;

      public class C {
          public static boolean checkReads() {
              return false;
          }

          public static boolean checkUses() {
              return false;
          }

          public static boolean checkProvides() {
              return false;
          }
      }
      ----------------------------------------------------------------
      with the class p/C
      ----------------------------------------------------------------
      package p;

      import p3.E;

      import java.util.ServiceLoader;

      public class C {
          public static boolean checkReads() {
              return E.getOne() == 1;
          }

          public static boolean checkUses() {
              return ServiceLoader.load(C.class.getModule().getLayer(), ServiceOne.class)
                      .findFirst()
                      .map(s -> s instanceof ServiceOneImpl)
                      .orElse(false);
          }

          public static boolean checkProvides() {
              return ServiceLoader.load(C.class.getModule().getLayer(), ServiceTwo.class)
                      .findFirst()
                      .map(s -> s instanceof ServiceTwoImpl)
                      .orElse(false);
          }
      }
      ----------------------------------------------------------------

      This retransformation is allowed by RI, although it contradicts the specification above because the transformed class contains extra public static final InnerClass Lookup and methods:

      private static synthetic Method lambda$checkProvides$1:"(Lp/ServiceTwo;)Ljava/lang/Boolean;"
      private static synthetic Method lambda$checkUses$0:"(Lp/ServiceOne;)Ljava/lang/Boolean;"

      The specification should be weakened according to accessibility of methods and/or fields(?).

            sspitsyn Serguei Spitsyn
            lkuskov Leonid Kuskov
            Votes:
            0 Vote for this issue
            Watchers:
            15 Start watching this issue

              Created:
              Updated:
              Resolved: