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

    Details

    • Subcomponent:
    • Introduced In Version:
      9
    • CPU:
      generic
    • OS:
      generic

      Description

      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 to add private methods, inner classes 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 contradict to the assertion 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 assertion should be weaken according to accesibility of methods, fields(?)

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                sspitsyn Serguei Spitsyn
                Reporter:
                lkuskov Leonid Kuskov
              • Votes:
                0 Vote for this issue
                Watchers:
                14 Start watching this issue

                Dates

                • Created:
                  Updated: