Skip to content

available() does not behave correctly when reading stored entries from a NestedJarFile #47056

@moritz1895

Description

@moritz1895

In JarEntryInputStream of NestedJarFile the remaining variable isn't initialized correctly.
This leads to invalid results when available() is called.

For example, in a Spring Boot application on the z/OS mainframe this can lead to a serious startup problem, when a JAR manifest is loaded, which is provided through a JAR entry of zip type STORED.
This is because the IBM Semeru Runtime Certified Edition for z/OS provides an alternative implementation of java.util.jar.Manifest. This implementation wraps most kinds of input streams into com.ibm.jvm.io.LocalizedInputStream.
Unfortunately we don't have access to the corresponding source code. However, according to our analysis the implementation makes use of the available()-method to peek into the data in order to identify if it's ASCII-encoded.
Since the remaining variable is not initialized, the implementation fails to peek into the data. That's why it defaults to the EBCDIC-1047 codepage. Consequently the input stream reading does not result in valid manifest data.

An example exception trace looks like :

Exception in thread "main" java.lang.reflect.InvocationTargetException
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:575)
        at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:102)
        at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:64)
        at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:40)
Caused by: java.io.UncheckedIOException: java.io.IOException: invalid header field (line 1)
        at org.springframework.boot.loader.jar.NestedJarFile.getManifestInfo(NestedJarFile.java:325)
        at org.springframework.boot.loader.zip.ZipContent.lambda$getInfo$0(ZipContent.java:326)
        at java.base/java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1693)
        at org.springframework.boot.loader.zip.ZipContent.getInfo(ZipContent.java:324)
        at org.springframework.boot.loader.jar.NestedJarFile.getManifestInfo(NestedJarFile.java:307)
        at org.springframework.boot.loader.jar.NestedJarFile.getVersionedContentEntry(NestedJarFile.java:276)
        at org.springframework.boot.loader.jar.NestedJarFile.hasEntry(NestedJarFile.java:247)
        at org.springframework.boot.loader.net.protocol.jar.JarUrlClassLoader.hasEntry(JarUrlClassLoader.java:174)
        at org.springframework.boot.loader.net.protocol.jar.JarUrlClassLoader.definePackage(JarUrlClassLoader.java:148)
        at org.springframework.boot.loader.net.protocol.jar.JarUrlClassLoader.definePackageIfNecessary(JarUrlClassLoader.java:129)
        at org.springframework.boot.loader.net.protocol.jar.JarUrlClassLoader.loadClass(JarUrlClassLoader.java:102)
        at org.springframework.boot.loader.launch.LaunchedClassLoader.loadClass(LaunchedClassLoader.java:91)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:1092)
        at org.example.SpringBootTest.main(SpringBootTest.java:10)
        ... 7 more
Caused by: java.io.IOException: invalid header field (line 1)
        at java.base/java.util.jar.Attributes.read(Attributes.java:406)
        at java.base/java.util.jar.Manifest.read(Manifest.java:297)
        at java.base/java.util.jar.Manifest.<init>(Manifest.java:107)
        at java.base/java.util.jar.Manifest.<init>(Manifest.java:83)
        at org.springframework.boot.loader.jar.NestedJarFile.getManifestInfo(NestedJarFile.java:320)
        ... 20 more

This has been tested with Spring Boot 3.5.3 under:

IBM Semeru Runtime Certified Edition for z/OS 17.0.15.0 (build 17.0.15+6)
IBM J9 VM 17.0.15.0 (build z/OS-Release-17.0.15.0-b02, JRE 17 z/OS s390x-64-Bit Compressed References 20250515_81 (JIT enabled, AOT enabled)
OpenJ9   - c54a416442c
OMR      - 83105fc1fae
IBM      - e7592ac
JCL      - 5510ecc8376 based on jdk-17.0.15+6)

The bug is still present in the main branch.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions