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

Assertion failure when symlink (with different name) is used for lib/modules file



    • Bug
    • Resolution: Fixed
    • P2
    • 13
    • 11, 12, 13
    • hotspot
    • b14
    • Verified


      If a symbolic link is used for lib/modules and the actual content/file name is not 'modules', the VM crashes with the following assertion with a slowdebug build:

      # To suppress the following error report, specify this argument
      # after -XX: or in .hotspotrc: SuppressErrorAt=/classLoader.cpp:740
      # A fatal error has been detected by the Java Runtime Environment:
      # Internal Error (/.../jdk/src/hotspot/share/classfile/classLoader.cpp:740), pid=223592, tid=223614
      # assert(new_entry != __null && new_entry->is_modules_image()) failed: No java runtime image present
      # JRE version: (13.0) (slowdebug build )
      # Java VM: OpenJDK 64-Bit Server VM (slowdebug 13-internal+0-adhoc.jianglizhou.jdk, mixed mode, aot, sharing, tiered, compressed oops, g1 gc, linux-amd64)
      # Problematic frame:
      # V [libjvm.so+0x798851] ClassLoader::setup_boot_search_path(char const*)+0x319
      # No core dump will be written. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again

      To reproduce:
      1) rename lib/modules to lib/0, then create a link to lib/0 as lib/modules
      2) bin/java -version

      I will also try to create a jtreg test.



      The ClassLoader::is_modules_image(char*source) API was poorly designed. Trying to fix its implementation caused more confusion during code review.

      This API is called only in 3 cases:

      1. In InstanceKlass::print_class_load_logging() to translate the source of "<javahome>/lib/modules" to "jrt:<module.name>". The reason is classes such as java.lang.Object are loaded before the module system is fully initialized, but we still want to print out the source as "jrt:java.base" to be consistent with other classes from the modules file (aka jrt: file system).

      2. In ClassLoader::record_result(), called only during CDS dump time, to see if a class's shared_classpath_index should be 0.

      3. In ClassFileParser::parse_stream, when dumping the loaded class list, to skip classes that are not loaded from the modules image, for the NULL and platform loaders.

      In all 3 cases, this API is intended to handle only classes loaded by a built-in class loader (NULL, platform, system). It's never intended to return true for classes loaded by any other class loaders.

      [A] if the class is loaded by the NULL class loader, this API should return true only if the class is loaded by ClassPathImageEntry -- this is the only case where the NULL class loader would load a class from the modules image.

      [B] If the class is loaded by the platform/system loaders, the source is always derived from a URL (see line 761 of the following call stack), so it will always be "<protocol>:/<path>", and will never be the bare pathname "<javahome>/lib/modules"


          java.lang.ClassLoader.defineClass2(Native Method)


      This only change we need to make to fix the reported issue is to address [A]. Doing a strcmp on the source will lead to question about pathname canonicalization, file system case insensitivity, etc., just more maintanence headache down the road.

      Instead, we should replace this API by simply putting a boolean in the ClassFileStream to indicate that we are loading a class from ClassPathImageEntry.




            iklam Ioi Lam
            jiangli Jiangli Zhou
            0 Vote for this issue
            9 Start watching this issue