6687968: PNGImageReader leaks native memory through an Inflater.
Reviewed-by: igor, prr
--- a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java Tue Jul 22 11:24:32 2008 -0700
+++ b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java Fri Jul 25 14:46:38 2008 +0400
@@ -616,10 +616,15 @@
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();
}
@@ -1244,13 +1249,26 @@
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);
@@ -1283,6 +1301,10 @@
}
} catch (IOException e) {
throw new IIOException("Error reading PNG image data", e);
+ } finally {
+ if (inf != null) {
+ inf.end();
+ }
}
}
--- a/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java Tue Jul 22 11:24:32 2008 -0700
+++ b/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java Fri Jul 25 14:46:38 2008 +0400
@@ -244,13 +244,17 @@
}
public void finish() throws IOException {
- if (!def.finished()) {
- def.finish();
- while (!def.finished()) {
- deflate();
+ try {
+ if (!def.finished()) {
+ def.finish();
+ while (!def.finished()) {
+ deflate();
+ }
}
+ finishChunk();
+ } finally {
+ def.end();
}
- finishChunk();
}
protected void finalize() throws Throwable {
@@ -928,23 +932,24 @@
// 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;
+ 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);
}
- } else {
- encodePass(ios, image, 0, 0, 1, 1);
+ } finally {
+ ios.finish();
}
-
- ios.finish();
}
private void writeIEND() throws IOException {