7003462: cannot read InputStream returned by java.util.ZipFile.getInputStream(ZipEntry)
Summary: The returned InflatedInputStream object should be kept in map streams
Reviewed-by: alanb
--- a/jdk/src/share/classes/java/util/zip/ZipFile.java Mon Dec 13 15:07:20 2010 +0000
+++ b/jdk/src/share/classes/java/util/zip/ZipFile.java Mon Dec 13 14:12:56 2010 -0800
@@ -315,7 +315,7 @@
private static native void freeEntry(long jzfile, long jzentry);
// the outstanding inputstreams that need to be closed.
- private Set<ZipFileInputStream> streams = new HashSet<ZipFileInputStream>();
+ private Set<InputStream> streams = new HashSet<>();
/**
* Returns an input stream for reading the contents of the specified
@@ -348,55 +348,58 @@
return null;
}
in = new ZipFileInputStream(jzentry);
- streams.add(in);
- }
- final ZipFileInputStream zfin = in;
- switch (getEntryMethod(jzentry)) {
- case STORED:
- return zfin;
- case DEFLATED:
- // MORE: Compute good size for inflater stream:
- long size = getEntrySize(jzentry) + 2; // Inflater likes a bit of slack
- if (size > 65536) size = 8192;
- if (size <= 0) size = 4096;
- return new InflaterInputStream(zfin, getInflater(), (int)size) {
- private boolean isClosed = false;
- public void close() throws IOException {
- if (!isClosed) {
- releaseInflater(inf);
- this.in.close();
- isClosed = true;
+ switch (getEntryMethod(jzentry)) {
+ case STORED:
+ streams.add(in);
+ return in;
+ case DEFLATED:
+ final ZipFileInputStream zfin = in;
+ // MORE: Compute good size for inflater stream:
+ long size = getEntrySize(jzentry) + 2; // Inflater likes a bit of slack
+ if (size > 65536) size = 8192;
+ if (size <= 0) size = 4096;
+ InputStream is = new InflaterInputStream(zfin, getInflater(), (int)size) {
+ private boolean isClosed = false;
+
+ public void close() throws IOException {
+ if (!isClosed) {
+ super.close();
+ releaseInflater(inf);
+ isClosed = true;
+ }
}
- }
- // Override fill() method to provide an extra "dummy" byte
- // at the end of the input stream. This is required when
- // using the "nowrap" Inflater option.
- protected void fill() throws IOException {
- if (eof) {
- throw new EOFException(
- "Unexpected end of ZLIB input stream");
- }
- len = this.in.read(buf, 0, buf.length);
- if (len == -1) {
- buf[0] = 0;
- len = 1;
- eof = true;
+ // Override fill() method to provide an extra "dummy" byte
+ // at the end of the input stream. This is required when
+ // using the "nowrap" Inflater option.
+ protected void fill() throws IOException {
+ if (eof) {
+ throw new EOFException(
+ "Unexpected end of ZLIB input stream");
+ }
+ len = this.in.read(buf, 0, buf.length);
+ if (len == -1) {
+ buf[0] = 0;
+ len = 1;
+ eof = true;
+ }
+ inf.setInput(buf, 0, len);
}
- inf.setInput(buf, 0, len);
- }
- private boolean eof;
+ private boolean eof;
- public int available() throws IOException {
- if (isClosed)
- return 0;
- long avail = zfin.size() - inf.getBytesWritten();
- return avail > (long) Integer.MAX_VALUE ?
- Integer.MAX_VALUE : (int) avail;
- }
- };
- default:
- throw new ZipException("invalid compression method");
+ public int available() throws IOException {
+ if (isClosed)
+ return 0;
+ long avail = zfin.size() - inf.getBytesWritten();
+ return avail > (long) Integer.MAX_VALUE ?
+ Integer.MAX_VALUE : (int) avail;
+ }
+ };
+ streams.add(is);
+ return is;
+ default:
+ throw new ZipException("invalid compression method");
+ }
}
}
@@ -539,9 +542,9 @@
closeRequested = true;
if (streams.size() !=0) {
- Set<ZipFileInputStream> copy = streams;
- streams = new HashSet<ZipFileInputStream>();
- for (ZipFileInputStream is: copy)
+ Set<InputStream> copy = streams;
+ streams = new HashSet<InputStream>();
+ for (InputStream is: copy)
is.close();
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/zip/ZipFile/FinalizeInflater.java Mon Dec 13 14:12:56 2010 -0800
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ @bug 7003462
+ @summary Make sure cached Inflater does not get finalized.
+ */
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+public class FinalizeInflater {
+
+ public static void main(String[] args) throws Throwable {
+ try (ZipFile zf = new ZipFile(new File(System.getProperty("test.src", "."), "input.zip")))
+ {
+ ZipEntry ze = zf.getEntry("ReadZip.java");
+ read(zf.getInputStream(ze));
+ System.gc();
+ System.runFinalization();
+ System.gc();
+ // read again
+ read(zf.getInputStream(ze));
+ }
+ }
+
+ private static void read(InputStream is)
+ throws IOException
+ {
+ Wrapper wrapper = new Wrapper(is);
+ byte[] buffer = new byte[32];
+ try {
+ while(is.read(buffer)>0){}
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ }
+ }
+
+ static class Wrapper{
+ InputStream is;
+ public Wrapper(InputStream is) {
+ this.is = is;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+ is.close();
+ }
+ }
+}