JDK-8191431 : Reading multiple PNG images with unique IDAT chunk positions will cause IIOException
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.imageio
  • Affected Version: 10
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2017-11-16
  • Updated: 2017-12-01
  • Resolved: 2017-11-23
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 10
10 b34Fixed
Related Reports
Relates :  
Description
Using the same PNGImageReader to read multiple images may lead to failures. To reproduce, please download the attached diff and apply it to a recent (consolidated) JDK checkout. It should add test "test/jdk/javax/imageio/plugins/png/ResetImageStartPosition.java" (+2 test images). Run the test, it you should see it fail with:
---
java.lang.IllegalStateException: javax.imageio.IIOException: Error reading PNG image data
	at PNGRead.read(PNGRead.java:30)
	at PNGRead.main(PNGRead.java:19)
	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 java.base/java.lang.Thread.run(Thread.java:844)
Caused by: javax.imageio.IIOException: Error reading PNG image data
	at java.desktop/com.sun.imageio.plugins.png.PNGImageReader.readImage(PNGImageReader.java:1405)
	at java.desktop/com.sun.imageio.plugins.png.PNGImageReader.read(PNGImageReader.java:1674)
	at PNGRead.read(PNGRead.java:28)
	... 7 more
Caused by: java.util.zip.ZipException: incorrect header check
	at java.base/java.util.zip.InflaterInputStream.read(InflaterInputStream.java:165)
	at java.base/java.io.BufferedInputStream.fill(BufferedInputStream.java:252)
	at java.base/java.io.BufferedInputStream.read(BufferedInputStream.java:271)
	at java.base/java.io.FilterInputStream.read(FilterInputStream.java:83)
	at java.desktop/com.sun.imageio.plugins.png.PNGImageReader.decodePass(PNGImageReader.java:1172)
	at java.desktop/com.sun.imageio.plugins.png.PNGImageReader.decodeImage(PNGImageReader.java:1275)
	at java.desktop/com.sun.imageio.plugins.png.PNGImageReader.readImage(PNGImageReader.java:1396)
	... 9 more
---

It fails when it read the "metal_minimize_rollover.png" for the second time (after reading "pause.png"). It is able to read the "metal_minimize_rollover.png" at the beginning of the  test, so there does not appear to be anything wrong with the image itself.

The reason appears to be that:
PNGImageReader.imageStartPosition is set while reading "pause.png", but reset neither in PNGImageReader.setInput, nor while reading the last image, so the stray value from reading the "pause.png" is used, which then lead to the problem. Note that the javadoc for ImageReader.setInput(Object, boolean, boolean) says (snipped):
---
     * <p> Subclasses should take care to remove any cached
     * information based on the previous stream, such as header
     * information or partially decoded image data.
---

I.e. it would seem appropriate to clear the imageStartPosition inside PNGImageReader.setInput (PNGImageReader.resetStreamSettings).
Comments
We can create a PNG image without palette and another with palette to get two images with different IDAT start position and we can use them to reproduce the issue. Attached the updated test case PngMultipleImageReadTest.java with which we can reproduce the issue without the need for external image files.
20-11-2017

We cant use test images present in attachment for OpenJDK code as it contains considerable content in IDAT chunk. We need 2 image streams where there is a difference in IDAT start position between streams to reproduce the issue.
20-11-2017

Issue is happening because of changes present in JDK-8164971. JDK-8164971 change checks for imageStartPosition, if it is equal to -1L then only it updates the imageStartPosition. if (imageStartPosition == -1L) { /* * PNGs may contain multiple IDAT chunks containing * a portion of image data. We store the position of * the first IDAT chunk and continue with iteration * of other chunks that follow image data. */ imageStartPosition = stream.getStreamPosition() - 8; } In scenarios where we are trying to read multiple images using same reader instance and if actual start of IDAT chunk position differs between these images then we will get IIOException as we are seeing in this bug. Between different read calls we should reset the imageStartPosition to -1L to get desired results.
20-11-2017

Checked in latest JDK 10 workspace. Observation : Only when we read pause.png first and then metal_minimize_rollover.png we say this issue. In any other combinations like reading same image twice or metal_minimize_rollover.png and then pause.png we are not seeing failures. Also as mentioned when we read individual images test runs fine.
20-11-2017