6687968: PNGImageReader leaks native memory through an Inflater
Reviewed-by: igor, prr
This commit is contained in:
parent
bd5f86fee1
commit
9d9f5afb8e
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user