JDK-2195810 : PNGImageReader leaks native memory through an Inflater.
  • Type: Backport
  • Backport of: JDK-6687968
  • Component: client-libs
  • Sub-Component: javax.imageio
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2010-07-17
  • Updated: 2011-01-19
  • Resolved: 2010-07-17
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 7 Other
7Fixed OpenJDK6Fixed
Comments
SUGGESTED FIX # HG changeset patch # User bae # Date 1216982798 -14400 # Node ID f63ef918ce3a1c4d403a85796dbb5a288539e46e # Parent b577c70564b8053092bf35f012fa29efe22f56c9 6687968: PNGImageReader leaks native memory through an Inflater. Reviewed-by: igor, prr --- a/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java Mon Aug 04 18:50:43 2008 +0400 +++ b/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java Fri Jul 25 14:46:38 2008 +0400 @@ -618,10 +618,15 @@ public class PNGImageReader extends Imag private static String inflate(byte[] b) throws IOException { InputStream bais = new ByteArrayInputStream(b); InputStream iis = new InflaterInputStream(bais); + StringBuilder sb = new StringBuilder(80); int c; - while ((c = iis.read()) != -1) { - sb.append((char)c); + try { + while ((c = iis.read()) != -1) { + sb.append((char)c); + } + } finally { + iis.close(); } return sb.toString(); } @@ -1246,13 +1251,26 @@ public class PNGImageReader extends Imag destinationBands = param.getDestinationBands(); destinationOffset = param.getDestinationOffset(); } - + Inflater inf = null; try { stream.seek(imageStartPosition); Enumeration e = new PNGImageDataEnumeration(stream); InputStream is = new SequenceInputStream(e); - is = new InflaterInputStream(is, new Inflater()); + + /* InflaterInputStream uses an Inflater instance which consumes + * native (non-GC visible) resources. This is normally implicitly + * freed when the stream is closed. However since the + * InflaterInputStream wraps a client-supplied input stream, + * we cannot close it. + * But the app may depend on GC finalization to close the stream. + * Therefore to ensure timely freeing of native resources we + * explicitly create the Inflater instance and free its resources + * when we are done with the InflaterInputStream by calling + * inf.end(); + */ + inf = new Inflater(); + is = new InflaterInputStream(is, inf); is = new BufferedInputStream(is); this.pixelStream = new DataInputStream(is); @@ -1285,6 +1303,10 @@ public class PNGImageReader extends Imag } } catch (IOException e) { throw new IIOException("Error reading PNG image data", e); + } finally { + if (inf != null) { + inf.end(); + } } } --- a/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java Mon Aug 04 18:50:43 2008 +0400 +++ b/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java Fri Jul 25 14:46:38 2008 +0400 @@ -244,13 +244,17 @@ final class IDATOutputStream extends Ima } public void finish() throws IOException { - if (!def.finished()) { - def.finish(); - while (!def.finished()) { - deflate(); - } - } - finishChunk(); + try { + if (!def.finished()) { + def.finish(); + while (!def.finished()) { + deflate(); + } + } + finishChunk(); + } finally { + def.end(); + } } protected void finalize() throws Throwable { @@ -928,23 +932,24 @@ public class PNGImageWriter extends Imag // Use sourceXOffset, etc. private void write_IDAT(RenderedImage image) throws IOException { IDATOutputStream ios = new IDATOutputStream(stream, 32768); - - if (metadata.IHDR_interlaceMethod == 1) { - for (int i = 0; i < 7; i++) { - encodePass(ios, image, - PNGImageReader.adam7XOffset[i], - PNGImageReader.adam7YOffset[i], - PNGImageReader.adam7XSubsampling[i], - PNGImageReader.adam7YSubsampling[i]); - if (abortRequested()) { - break; - } - } - } else { - encodePass(ios, image, 0, 0, 1, 1); - } - - ios.finish(); + try { + if (metadata.IHDR_interlaceMethod == 1) { + for (int i = 0; i < 7; i++) { + encodePass(ios, image, + PNGImageReader.adam7XOffset[i], + PNGImageReader.adam7YOffset[i], + PNGImageReader.adam7XSubsampling[i], + PNGImageReader.adam7YSubsampling[i]); + if (abortRequested()) { + break; + } + } + } else { + encodePass(ios, image, 0, 0, 1, 1); + } + } finally { + ios.finish(); + } } private void writeIEND() throws IOException {
17-07-2010

EVALUATION Yes.
17-07-2010

PUBLIC COMMENTS See http://hg.openjdk.java.net/jdk6/jdk6-gate/jdk/rev/f63ef918ce3a
17-07-2010