6687968: PNGImageReader leaks native memory through an Inflater

Reviewed-by: igor, prr
This commit is contained in:
Andrew Brygin 2008-07-25 14:46:38 +04:00
parent bd5f86fee1
commit 9d9f5afb8e
2 changed files with 50 additions and 23 deletions

View File

@ -616,10 +616,15 @@ public class PNGImageReader extends ImageReader {
private static String inflate(byte[] b) throws IOException { private static String inflate(byte[] b) throws IOException {
InputStream bais = new ByteArrayInputStream(b); InputStream bais = new ByteArrayInputStream(b);
InputStream iis = new InflaterInputStream(bais); InputStream iis = new InflaterInputStream(bais);
StringBuilder sb = new StringBuilder(80); StringBuilder sb = new StringBuilder(80);
int c; int c;
while ((c = iis.read()) != -1) { try {
sb.append((char)c); while ((c = iis.read()) != -1) {
sb.append((char)c);
}
} finally {
iis.close();
} }
return sb.toString(); return sb.toString();
} }
@ -1244,13 +1249,26 @@ public class PNGImageReader extends ImageReader {
destinationBands = param.getDestinationBands(); destinationBands = param.getDestinationBands();
destinationOffset = param.getDestinationOffset(); destinationOffset = param.getDestinationOffset();
} }
Inflater inf = null;
try { try {
stream.seek(imageStartPosition); stream.seek(imageStartPosition);
Enumeration e = new PNGImageDataEnumeration(stream); Enumeration e = new PNGImageDataEnumeration(stream);
InputStream is = new SequenceInputStream(e); 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); is = new BufferedInputStream(is);
this.pixelStream = new DataInputStream(is); this.pixelStream = new DataInputStream(is);
@ -1283,6 +1301,10 @@ public class PNGImageReader extends ImageReader {
} }
} catch (IOException e) { } catch (IOException e) {
throw new IIOException("Error reading PNG image data", e); throw new IIOException("Error reading PNG image data", e);
} finally {
if (inf != null) {
inf.end();
}
} }
} }

View File

@ -244,13 +244,17 @@ final class IDATOutputStream extends ImageOutputStreamImpl {
} }
public void finish() throws IOException { public void finish() throws IOException {
if (!def.finished()) { try {
def.finish(); if (!def.finished()) {
while (!def.finished()) { def.finish();
deflate(); while (!def.finished()) {
deflate();
}
} }
finishChunk();
} finally {
def.end();
} }
finishChunk();
} }
protected void finalize() throws Throwable { protected void finalize() throws Throwable {
@ -928,23 +932,24 @@ public class PNGImageWriter extends ImageWriter {
// Use sourceXOffset, etc. // Use sourceXOffset, etc.
private void write_IDAT(RenderedImage image) throws IOException { private void write_IDAT(RenderedImage image) throws IOException {
IDATOutputStream ios = new IDATOutputStream(stream, 32768); IDATOutputStream ios = new IDATOutputStream(stream, 32768);
try {
if (metadata.IHDR_interlaceMethod == 1) { if (metadata.IHDR_interlaceMethod == 1) {
for (int i = 0; i < 7; i++) { for (int i = 0; i < 7; i++) {
encodePass(ios, image, encodePass(ios, image,
PNGImageReader.adam7XOffset[i], PNGImageReader.adam7XOffset[i],
PNGImageReader.adam7YOffset[i], PNGImageReader.adam7YOffset[i],
PNGImageReader.adam7XSubsampling[i], PNGImageReader.adam7XSubsampling[i],
PNGImageReader.adam7YSubsampling[i]); PNGImageReader.adam7YSubsampling[i]);
if (abortRequested()) { if (abortRequested()) {
break; break;
}
} }
} else {
encodePass(ios, image, 0, 0, 1, 1);
} }
} else { } finally {
encodePass(ios, image, 0, 0, 1, 1); ios.finish();
} }
ios.finish();
} }
private void writeIEND() throws IOException { private void writeIEND() throws IOException {