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

SA throws WrongTypeException because of static field check

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Won't Fix
    • Icon: P4 P4
    • 23
    • 11, 17
    • hotspot
    • x86_64
    • linux

      ADDITIONAL SYSTEM INFORMATION :
      This bug produce on OSX and linux, haven't test other OSes.
      Affect java versions: 11 to 17, haven't test older versions or versions after 17.

      A DESCRIPTION OF THE PROBLEM :
      Service Ablity offers function which can traverse all loaded classes using VM.getVM().getClassLoaderGraph(). I write an attacher to test this method, but the attacher always exits abnormally. The attacher code is listed in source code part of this bug report. The attacher exits after throwing WrongTypeException, see the actual result part below, I paste full stack trace there.

      This bug seems to be HotspotAgent consider the dictionary field of ClassLoaderData is static.


      public class ClassLoaderData extends VMObject {
        static {
          VM.registerVMInitializedObserver(new java.util.Observer() {
              public void update(java.util.Observable o, Object data) {
                initialize(VM.getVM().getTypeDataBase());
              }
            });
        }

        private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
          Type type = db.lookupType("ClassLoaderData");
          // omit for simplicity
          dictionaryField = type.getAddressField("_dictionary");
        }
      }

      in the above code, dictionary is assigned using type.getAddressField which is actually a BasicAddressFieldWrapper. The getValue method of the wrapper will call BasicField.getAddress method which will check if the field is static. But dictionary field of ClassloaderData is not static, according to source code:

      // ClassLoaderData.hpp
      class ClassLoaderData : public CHeapObj<mtClass> {
        Dictionary* _dictionary; // The loaded InstanceKlasses, including initiated by this class loader
      }

      the attacher then throws WrongTypeException and exits.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      First run any java program, use jps command to get pid (assume it is 35278) of this process.

      run following command to compile source code:

      javac --add-exports jdk.hotspot.agent/sun.jvm.hotspot.classfile=ALL-UNNAMED --add-exports jdk.hotspot.agent/sun.jvm.hotspot.oops=ALL-UNNAMED --add-exports jdk.hotspot.agent/sun.jvm.hotspot=ALL-UNNAMED --add-exports jdk.hotspot.agent/sun.jvm.hotspot.runtime=ALL-UNNAMED --add-modules=jdk.hotspot.agent SATest.java

      then run following command to attach to the running process:
      java --add-exports jdk.hotspot.agent/sun.jvm.hotspot.classfile=ALL-UNNAMED --add-exports jdk.hotspot.agent/sun.jvm.hotspot.oops=ALL-UNNAMED --add-exports jdk.hotspot.agent/sun.jvm.hotspot=ALL-UNNAMED --add-exports jdk.hotspot.agent/sun.jvm.hotspot.runtime=ALL-UNNAMED --add-modules=jdk.hotspot.agent SATest 35278

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The SATest program should print all classes and their classloader, then exit normally.
      ACTUAL -
      The SATest process exits because of WrongTypeException.

      Exception in thread "main" sun.jvm.hotspot.types.WrongTypeException
      at jdk.hotspot.agent/sun.jvm.hotspot.types.basic.BasicField.getAddress(BasicField.java:246)
      at jdk.hotspot.agent/sun.jvm.hotspot.types.basic.BasicAddressFieldWrapper.getValue(BasicAddressFieldWrapper.java:48)
      at jdk.hotspot.agent/sun.jvm.hotspot.classfile.ClassLoaderData.dictionary(ClassLoaderData.java:64)
      at jdk.hotspot.agent/sun.jvm.hotspot.classfile.ClassLoaderData.allEntriesDo(ClassLoaderData.java:120)
      at jdk.hotspot.agent/sun.jvm.hotspot.classfile.ClassLoaderDataGraph.allEntriesDo(ClassLoaderDataGraph.java:92)
      at SATest.main(SATest.java:11)

      ---------- BEGIN SOURCE ----------

      import sun.jvm.hotspot.HotSpotAgent;
      import sun.jvm.hotspot.runtime.VM;

      public class SATest {
          public static void main(String[] args) throws Exception {
              HotSpotAgent hotSpotAgent = new HotSpotAgent();

              int pid = Integer.parseInt(args[0]);
              hotSpotAgent.attach(pid);
              VM.getVM().getClassLoaderDataGraph().allEntriesDo(
                      (klass, loader) -> {
                          System.out.println(klass.getName() + " " + loader);
                      }
              );
          }

      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      I've found two workarounds:

      1. use ClassloaderGraph.classesDo method instead.
      This method offers similar functionality but does not throw exception.

      2. change hotspot source code and rebuild jvm

      // ClassLoaderData.java
      public class ClassLoaderData extends VMObject {
        public Dictionary dictionary() {
            Address addr = dictionaryField.getValue(getAddress());
            if (addr == null) {
                System.out.println("_dictionary is null " + getAddress());
                return null;
            }
            return new Dictionary(addr)
        }
      }

      The BasicAddressFieldWrapper has another getValue method which accepts an Address parameter. This version of method checks if the specified field is nonStatic, and this seems to be the expected callee method.

      FREQUENCY : always


            cjplummer Chris Plummer
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: