-
Bug
-
Resolution: Fixed
-
P4
-
8, 11, 14, 15
-
b13
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8316296 | 11.0.22-oracle | Ramesh Gangadhar | P4 | Resolved | Fixed | b01 |
JDK-8318830 | 11.0.22 | Kangcheng Xu | P4 | Resolved | Fixed | b01 |
JarUtils.updateJar() and JarUtils.updateJarFile() update jar files by reading JarEntry-s from a source jar file and writing these exact JarEntry-s to the destination jar file follwoed be the inflated and re-deflated data belonging to this entry.
This approach is not correct, because JarEntry contains both, the compressed and uncomressed size of the corresponding entry. But the original Defalter which initially compressed that entry can be either different from the current one or it might have used a different compression level compared to the current Deflater which re-deflates the entry data.
When the newly created entry is closed, the new compressed size will be checked against the original compressed size if that was recorded in the JarEntry and an exception will be thrown, when they differ:
java.util.zip.ZipException: invalid entry compressed size (expected 237 but got 238 bytes)
at java.base/java.util.zip.ZipOutputStream.closeEntry(ZipOutputStream.java:267)
at java.base/java.util.zip.ZipOutputStream.putNextEntry(ZipOutputStream.java:192)
at java.base/java.util.jar.JarOutputStream.putNextEntry(JarOutputStream.java:108)
at jdk.test.lib.util.JarUtils.updateJar(JarUtils.java:294)
at jdk.test.lib.util.JarUtils.updateJar(JarUtils.java:252)
at HasUnsignedEntryTest.start(HasUnsignedEntryTest.java:77)
at HasUnsignedEntryTest.main(HasUnsignedEntryTest.java:44)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:
43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at com.sun.javatest.regtest.agent.MainWrapper$MainThread.run(MainWrapper.java:127)
at java.base/java.lang.Thread.run(Thread.java:832)
Suppressed: java.util.zip.ZipException: invalid entry compressed size (expected 237 but got 238 bytes)
at java.base/java.util.zip.ZipOutputStream.closeEntry(ZipOutputStream.java:267)
at java.base/java.util.zip.ZipOutputStream.finish(ZipOutputStream.java:360)
at java.base/java.util.zip.DeflaterOutputStream.close(DeflaterOutputStream.java:237)
at java.base/java.util.zip.ZipOutputStream.close(ZipOutputStream.java:377)
at jdk.test.lib.util.JarUtils.updateJar(JarUtils.java:280)
The fix is trivial. Instead of copying the JarEntry-s verbatim to the output stream, simply write newly created JarEntry-s to the output stream which only contain the entry name. This is also the way how this is handled by the jar tool, when it updates jar files.
This approach is not correct, because JarEntry contains both, the compressed and uncomressed size of the corresponding entry. But the original Defalter which initially compressed that entry can be either different from the current one or it might have used a different compression level compared to the current Deflater which re-deflates the entry data.
When the newly created entry is closed, the new compressed size will be checked against the original compressed size if that was recorded in the JarEntry and an exception will be thrown, when they differ:
java.util.zip.ZipException: invalid entry compressed size (expected 237 but got 238 bytes)
at java.base/java.util.zip.ZipOutputStream.closeEntry(ZipOutputStream.java:267)
at java.base/java.util.zip.ZipOutputStream.putNextEntry(ZipOutputStream.java:192)
at java.base/java.util.jar.JarOutputStream.putNextEntry(JarOutputStream.java:108)
at jdk.test.lib.util.JarUtils.updateJar(JarUtils.java:294)
at jdk.test.lib.util.JarUtils.updateJar(JarUtils.java:252)
at HasUnsignedEntryTest.start(HasUnsignedEntryTest.java:77)
at HasUnsignedEntryTest.main(HasUnsignedEntryTest.java:44)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:
43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at com.sun.javatest.regtest.agent.MainWrapper$MainThread.run(MainWrapper.java:127)
at java.base/java.lang.Thread.run(Thread.java:832)
Suppressed: java.util.zip.ZipException: invalid entry compressed size (expected 237 but got 238 bytes)
at java.base/java.util.zip.ZipOutputStream.closeEntry(ZipOutputStream.java:267)
at java.base/java.util.zip.ZipOutputStream.finish(ZipOutputStream.java:360)
at java.base/java.util.zip.DeflaterOutputStream.close(DeflaterOutputStream.java:237)
at java.base/java.util.zip.ZipOutputStream.close(ZipOutputStream.java:377)
at jdk.test.lib.util.JarUtils.updateJar(JarUtils.java:280)
The fix is trivial. Instead of copying the JarEntry-s verbatim to the output stream, simply write newly created JarEntry-s to the output stream which only contain the entry name. This is also the way how this is handled by the jar tool, when it updates jar files.
- backported by
-
JDK-8316296 jdk.test.lib.util.JarUtils updates jar files incorrectly
- Resolved
-
JDK-8318830 jdk.test.lib.util.JarUtils updates jar files incorrectly
- Resolved
- relates to
-
JDK-8240333 jmod incorrectly updates .jar and .jmod files during hashing
- Resolved
-
JDK-8253952 Refine ZipOutputStream.putNextEntry() to recalculate ZipEntry's compressed size
- Resolved
(1 links to)