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

Malformed system classes loaded by bootloader crash the JVM in product builds

XMLWordPrintable

    • Icon: Enhancement Enhancement
    • Resolution: Fixed
    • Icon: P4 P4
    • 24
    • None
    • hotspot
    • b22

      The JVM considers classes loaded by the bootloader to be trusted and will skip bytecode verification. The crash comes from a random location in ClassFileParser.cpp.

      Add the flag -Xverify:all and the flag "BytecodeVerificationLocal" will be set, turning on the verification of classes loaded by the bootloader.

      The problem comes from the malformed class:
      "jdk/internal/module/SystemModuleFinders$1$$Lambda"

      parse_interfaces() reads the length of 1 interface, described at offset 483.
      The class index for this interface is then read from offset 485; it is 0x1a (0n26).

      However, the value (type) at this index (0n26) is not a JVM_CONSTANT_Class, but JVM_CONSTANT_UTF8, representing the string "java/security/PrivilegedAction".
      With verification turned on, a java/lang/ClassFormatError will be thrown with the
      following message:
      "Interface name has bad constant pool index 26 in class file jdk.internal.module.SystemModuleFinders$1$$Lambda"

      Hence, with -Xverify:all you should see the following:
      "Error occurred during initialization of boot layer
      java.lang.InternalError: java.lang.ClassFormatError: Interface name has bad constant pool index 26 in class file jdk/internal/module/SystemModuleFinders$1$$Lambda
      Caused by: java.lang.ClassFormatError: Interface name has bad constant pool index 26 in class file jdk/internal/module/SystemModuleFinders$1$$Lambda"

      The crash report is an actual crash, not an assert (because it is a product build). The reason is here:

      // ClassFileParser.cpp

        inline void check_property(bool property,
                                   const char* msg,
                                   int index,
                                   TRAPS) const {
          if (_need_verify) {
            guarantee_property(property, msg, index, CHECK);
          } else {
            assert_property(property, msg, index, CHECK);
          }
        }

        inline void assert_property(bool b, const char* msg, int index, TRAPS) const {
        #ifdef ASSERT
          if (!b) {
            report_assert_property_failure(msg, index, THREAD);
          }
        #endif
        }

      This construction is not complete because no action is taken for product builds. This leads to crashes later, not at the point of error discovery.

      Perhaps the branch for !_need_verify in check_property() should be split: guarantee_property(), which throws ClassFormatError, for product builds, and assert_property() for non-product builds. (edited)

      An argument for this is that system classes are built mainly through core-libs, and it is more valuable for them to get a ClassFormatError compared to the VM crashing or asserting.

            dholmes David Holmes
            mgronlun Markus Grönlund
            Votes:
            0 Vote for this issue
            Watchers:
            10 Start watching this issue

              Created:
              Updated:
              Resolved: