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.
Comment From: wilkinsona
Thanks for the report, @moritz1895. I've pushed something that I believe should fix the described problem. It would be great if you could try 3.5.6-SNAPSHOT (available from https://repo.spring.io/snapshot) once this build has completed.
Comment From: moritz1895
Thank you for your fast and helpful solution. We can confirm the changes solved the problem!
Comment From: wilkinsona
Excellent. Thanks very much for testing a snapshot, @moritz1895. The changes will be released later this month (18 September).