JDK-8139297 : java.lang.NoClassDefFoundError: Could not initialize class jdk.internal.jimage.ImageNativeSubstrate
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang.module
  • Affected Version: 9
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2015-10-09
  • Updated: 2016-06-13
  • Resolved: 2015-10-12
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 9
9 b88Fixed
Related Reports
Relates :  
Description
Consider this test class:
---
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Paths;

public class JrtFsTest {

    public static void main(String[] args) throws URISyntaxException {
        Paths.get(new URI("jrt:/"));
    }

}
---

Compile it, and run it on JDK 8 like:
jdk8/bin/java -classpath <JDK9-image>/jrt-fs.jar:<path-to-test> JrtFsTest

This fails with:
---
Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class jdk.internal.jimage.ImageNativeSubstrate
        at jdk.internal.jimage.BasicImageReader.openImageSubstrate(BasicImageReader.java:60)
        at jdk.internal.jimage.BasicImageReader.<init>(BasicImageReader.java:46)
        at jdk.internal.jimage.ImageReader.<init>(ImageReader.java:65)
        at jdk.internal.jimage.ImageReader.open(ImageReader.java:75)
        at jdk.internal.jimage.ImageReader.open(ImageReader.java:82)
        at jdk.internal.jrtfs.JrtFileSystem.openImage(JrtFileSystem.java:93)
        at jdk.internal.jrtfs.JrtFileSystem.<init>(JrtFileSystem.java:108)
        at jdk.internal.jrtfs.JrtFileSystemProvider$1.<init>(JrtFileSystemProvider.java:113)
        at jdk.internal.jrtfs.JrtFileSystemProvider.getTheFileSystem(JrtFileSystemProvider.java:113)
        at jdk.internal.jrtfs.JrtFileSystemProvider.getPath(JrtFileSystemProvider.java:102)
        at java.nio.file.Paths.get(Paths.java:143)
        at JrtFsTest.main(JrtFsTest.java:8)
---

This is with jrt-fs.jar from:
$ java -version
java version "1.9.0-ea"
Java(TM) SE Runtime Environment (build 1.9.0-ea-b83)
Java HotSpot(TM) 64-Bit Server VM (build 1.9.0-ea-b83, mixed mode)

Running on:
$ java -version
java version "1.8.0_40"
Java(TM) SE Runtime Environment (build 1.8.0_40-b25)
Java HotSpot(TM) 64-Bit Server VM (build 25.40-b25, mixed mode)

Comments
I wonder if jrt-fs.jar should just not contain ImageNativeSubstrate at all. Filter it our during the build? It is just not interesting from a jrt-fs point of view. Any other types only used by ImageNativeSubstrate could be omitted also. In which case, CNFE would be the correct error to handle.
09-10-2015

Meaning jrtfs should test to see if is running in JDK 9 or better?
09-10-2015

LinkageError might be too general here and could hide issues, better to catch NCDFE and UnsatisfiedLinkError. Do we have an in issue created to fix the real issue here? The real issue I think is that the native implementation should only be used by jrtfs when it accessing the run-time image of the current VM.
09-10-2015

This issue is not related to JDK-8137056. It reproduces in a build without JDK-8137056. JDK-8137056 added a little hack into ImageNativeSubstrate to reflectively support the move of SharedSecrets from sun.misc to jdk.internal.misc, but this is in b85. This problem seems to have happened in b83 ( the test does not fail in b82 ). $ ~/binaries/jdk1.8.0_05/bin/java -cp ~/binaries/jdk1.9.0_b82/jrt-fs.jar:. JrtFsTest $ ~/binaries/jdk1.8.0_05/bin/java -cp ~/binaries/jdk1.9.0_b83/jrt-fs.jar:. JrtFsTest Exception in thread "main" java.lang.NoClassDefFoundError: Could not initialize class jdk.internal.jimage.ImageNativeSubstrate at jdk.internal.jimage.BasicImageReader.openImageSubstrate(BasicImageReader.java:60) at jdk.internal.jimage.BasicImageReader.<init>(BasicImageReader.java:46) at jdk.internal.jimage.ImageReader.<init>(ImageReader.java:65) at jdk.internal.jimage.ImageReader.open(ImageReader.java:75) at jdk.internal.jimage.ImageReader.open(ImageReader.java:82) at jdk.internal.jrtfs.JrtFileSystem.openImage(JrtFileSystem.java:93) at jdk.internal.jrtfs.JrtFileSystem.<init>(JrtFileSystem.java:108) at jdk.internal.jrtfs.JrtFileSystemProvider$1.<init>(JrtFileSystemProvider.java:113) at jdk.internal.jrtfs.JrtFileSystemProvider.getTheFileSystem(JrtFileSystemProvider.java:113) at jdk.internal.jrtfs.JrtFileSystemProvider.getPath(JrtFileSystemProvider.java:102) at java.nio.file.Paths.get(Paths.java:143) at JrtFsTest.main(JrtFsTest.java:8) The issue seems to be with the loading of libjimage from ImageNativeSubstrate, since this library does not exist in a JDK 8 build. An instrumented build shows: $ ~/binaries/jdk1.8.0_05/bin/java -cp build/linux-x86_64-normal-server-release/images/jdk/jrt-fs.jar:. JrtFsTest java.lang.UnsatisfiedLinkError: no jimage in java.library.path at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1857) at java.lang.Runtime.loadLibrary0(Runtime.java:870) at java.lang.System.loadLibrary(System.java:1119) at jdk.internal.jimage.ImageNativeSubstrate$1.run(ImageNativeSubstrate.java:39) at jdk.internal.jimage.ImageNativeSubstrate$1.run(ImageNativeSubstrate.java:34) at java.security.AccessController.doPrivileged(Native Method) at jdk.internal.jimage.ImageNativeSubstrate.<clinit>(ImageNativeSubstrate.java:33) at jdk.internal.jimage.BasicImageReader.openImageSubstrate(BasicImageReader.java:60) at jdk.internal.jimage.BasicImageReader.<init>(BasicImageReader.java:46) at jdk.internal.jimage.ImageReader.<init>(ImageReader.java:65) at jdk.internal.jimage.ImageReader.open(ImageReader.java:75) at jdk.internal.jimage.ImageReader.open(ImageReader.java:82) at jdk.internal.jrtfs.JrtFileSystem.openImage(JrtFileSystem.java:93) at jdk.internal.jrtfs.JrtFileSystem.<init>(JrtFileSystem.java:107) at jdk.internal.jrtfs.JrtFileSystemProvider$1.<init>(JrtFileSystemProvider.java:113) at jdk.internal.jrtfs.JrtFileSystemProvider.getTheFileSystem(JrtFileSystemProvider.java:113) at jdk.internal.jrtfs.JrtFileSystemProvider.getPath(JrtFileSystemProvider.java:102) at java.nio.file.Paths.get(Paths.java:143) at JrtFsTest.main(JrtFsTest.java:8) I see that the calling code already catches java.lang.UnsatisfiedLinkError, but it appears that the classloader is translating this into a NCDFE.
09-10-2015

I think it is fair game for an unchecked Exception or Error thrown during class initialization to result in a NCDFE. The code above, BasicImageReader, could catch java.lang.LinkageError, rather than UnsatisfiedLinkError. LinkageError is the supertype of NCDFE and UnsatisfiedLinkError. Just to note, this will be a temporary solution, until JDK-8137017 is resolved.
09-10-2015

But why is "the classloader is translating this into a NCDFE"
09-10-2015

As a short term solution that could work.
09-10-2015

Could have BasicImageReader catch the java.lang.NoClassDefFoundError as a short term workaround private static ImageSubstrate openImageSubstrate(String imagePath, ByteOrder byteOrder) throws IOException { ImageSubstrate substrate; try { substrate = ImageNativeSubstrate.openImage(imagePath, byteOrder); } catch (UnsatisfiedLinkError ex) { substrate = ImageJavaSubstrate.openImage(imagePath, byteOrder); } return substrate; }
09-10-2015

This seems a result of JDK-8137056, Chris created JDK-8137017 to follow-up on that topic.
09-10-2015

Not that I'm aware of. Is there a way to run an test, not on the target build? This looks like the error reported (NoClassDefFoundError) for the missing native code is not what is expected (UnsatisfiedLinkError.) and what is this? // TODO: Reinstate when the class below, NIOACCESS, is removed. //private static final JavaNioAccess NIOACCESS = // SharedSecrets.getJavaNioAccess(); Looks like someone didn't verify what happens on JDK8 (yes a test would have caught it.)
09-10-2015

Jim - do we have tests anywhere that are checking to ensure that the JDK 8 build of jrt-fs.jar is always working?
09-10-2015