Projects
Mega:23.09
openjdk-1.8.0
_service:tar_scm:8193682-Infinite-loop-in-ZipOu...
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:tar_scm:8193682-Infinite-loop-in-ZipOutputStream.close.patch of Package openjdk-1.8.0
From ba4213c7350e7a145a142d0cbe54718a8c92b93c Mon Sep 17 00:00:00 2001 Subject: 8193682: Infinite loop in ZipOutputStream.close() --- .../java/util/zip/DeflaterOutputStream.java | 9 +- .../java/util/zip/GZIPOutputStream.java | 38 +++-- .../java/util/zip/ZipOutputStream.java | 96 ++++++------ jdk/test/java/util/zip/CloseDeflaterTest.java | 147 ++++++++++++++++++ 4 files changed, 226 insertions(+), 64 deletions(-) create mode 100644 jdk/test/java/util/zip/CloseDeflaterTest.java diff --git a/jdk/src/share/classes/java/util/zip/DeflaterOutputStream.java b/jdk/src/share/classes/java/util/zip/DeflaterOutputStream.java index a1f768cae..f4cf79693 100644 --- a/jdk/src/share/classes/java/util/zip/DeflaterOutputStream.java +++ b/jdk/src/share/classes/java/util/zip/DeflaterOutputStream.java @@ -235,9 +235,12 @@ class DeflaterOutputStream extends FilterOutputStream { */ public void close() throws IOException { if (!closed) { - finish(); - if (usesDefaultDeflater) - def.end(); + try { + finish(); + } finally { + if (usesDefaultDeflater) + def.end(); + } out.close(); closed = true; } diff --git a/jdk/src/share/classes/java/util/zip/GZIPOutputStream.java b/jdk/src/share/classes/java/util/zip/GZIPOutputStream.java index 2c1cd409b..1c3f8592e 100644 --- a/jdk/src/share/classes/java/util/zip/GZIPOutputStream.java +++ b/jdk/src/share/classes/java/util/zip/GZIPOutputStream.java @@ -154,24 +154,30 @@ class GZIPOutputStream extends DeflaterOutputStream { */ public void finish() throws IOException { if (!def.finished()) { - def.finish(); - while (!def.finished()) { - int len = def.deflate(buf, 0, buf.length); - if (def.finished() && len <= buf.length - TRAILER_SIZE) { - // last deflater buffer. Fit trailer at the end - writeTrailer(buf, len); - len = len + TRAILER_SIZE; - out.write(buf, 0, len); - return; + try { + def.finish(); + while (!def.finished()) { + int len = def.deflate(buf, 0, buf.length); + if (def.finished() && len <= buf.length - TRAILER_SIZE) { + // last deflater buffer. Fit trailer at the end + writeTrailer(buf, len); + len = len + TRAILER_SIZE; + out.write(buf, 0, len); + return; + } + if (len > 0) + out.write(buf, 0, len); } - if (len > 0) - out.write(buf, 0, len); + // if we can't fit the trailer at the end of the last + // deflater buffer, we write it separately + byte[] trailer = new byte[TRAILER_SIZE]; + writeTrailer(trailer, 0); + out.write(trailer); + } catch (IOException e) { + if (usesDefaultDeflater) + def.end(); + throw e; } - // if we can't fit the trailer at the end of the last - // deflater buffer, we write it separately - byte[] trailer = new byte[TRAILER_SIZE]; - writeTrailer(trailer, 0); - out.write(trailer); } } diff --git a/jdk/src/share/classes/java/util/zip/ZipOutputStream.java b/jdk/src/share/classes/java/util/zip/ZipOutputStream.java index 6b480aa1d..f001ddf00 100644 --- a/jdk/src/share/classes/java/util/zip/ZipOutputStream.java +++ b/jdk/src/share/classes/java/util/zip/ZipOutputStream.java @@ -247,59 +247,65 @@ class ZipOutputStream extends DeflaterOutputStream implements ZipConstants { public void closeEntry() throws IOException { ensureOpen(); if (current != null) { - ZipEntry e = current.entry; - switch (e.method) { - case DEFLATED: - def.finish(); - while (!def.finished()) { - deflate(); - } - if ((e.flag & 8) == 0) { - // verify size, compressed size, and crc-32 settings - if (e.size != def.getBytesRead()) { - throw new ZipException( - "invalid entry size (expected " + e.size + - " but got " + def.getBytesRead() + " bytes)"); + try { + ZipEntry e = current.entry; + switch (e.method) { + case DEFLATED: + def.finish(); + while (!def.finished()) { + deflate(); } - if (e.csize != def.getBytesWritten()) { + if ((e.flag & 8) == 0) { + // verify size, compressed size, and crc-32 settings + if (e.size != def.getBytesRead()) { + throw new ZipException( + "invalid entry size (expected " + e.size + + " but got " + def.getBytesRead() + " bytes)"); + } + if (e.csize != def.getBytesWritten()) { + throw new ZipException( + "invalid entry compressed size (expected " + + e.csize + " but got " + def.getBytesWritten() + " bytes)"); + } + if (e.crc != crc.getValue()) { + throw new ZipException( + "invalid entry CRC-32 (expected 0x" + + Long.toHexString(e.crc) + " but got 0x" + + Long.toHexString(crc.getValue()) + ")"); + } + } else { + e.size = def.getBytesRead(); + e.csize = def.getBytesWritten(); + e.crc = crc.getValue(); + writeEXT(e); + } + def.reset(); + written += e.csize; + break; + case STORED: + // we already know that both e.size and e.csize are the same + if (e.size != written - locoff) { throw new ZipException( - "invalid entry compressed size (expected " + - e.csize + " but got " + def.getBytesWritten() + " bytes)"); + "invalid entry size (expected " + e.size + + " but got " + (written - locoff) + " bytes)"); } if (e.crc != crc.getValue()) { throw new ZipException( - "invalid entry CRC-32 (expected 0x" + - Long.toHexString(e.crc) + " but got 0x" + - Long.toHexString(crc.getValue()) + ")"); + "invalid entry crc-32 (expected 0x" + + Long.toHexString(e.crc) + " but got 0x" + + Long.toHexString(crc.getValue()) + ")"); } - } else { - e.size = def.getBytesRead(); - e.csize = def.getBytesWritten(); - e.crc = crc.getValue(); - writeEXT(e); + break; + default: + throw new ZipException("invalid compression method"); } - def.reset(); - written += e.csize; - break; - case STORED: - // we already know that both e.size and e.csize are the same - if (e.size != written - locoff) { - throw new ZipException( - "invalid entry size (expected " + e.size + - " but got " + (written - locoff) + " bytes)"); - } - if (e.crc != crc.getValue()) { - throw new ZipException( - "invalid entry crc-32 (expected 0x" + - Long.toHexString(e.crc) + " but got 0x" + - Long.toHexString(crc.getValue()) + ")"); - } - break; - default: - throw new ZipException("invalid compression method"); + crc.reset(); + current = null; + } catch (IOException e) { + if (usesDefaultDeflater && !(e instanceof ZipException)) + def.end(); + throw e; } - crc.reset(); - current = null; } } diff --git a/jdk/test/java/util/zip/CloseDeflaterTest.java b/jdk/test/java/util/zip/CloseDeflaterTest.java new file mode 100644 index 000000000..8aa4960f5 --- /dev/null +++ b/jdk/test/java/util/zip/CloseDeflaterTest.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2021, 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 8193682 + * @summary Test Infinite loop while writing on closed GZipOutputStream , ZipOutputStream and JarOutputStream. + * @run testng CloseDeflaterTest + */ +import java.io.*; +import java.util.Random; +import java.util.jar.JarOutputStream; +import java.util.zip.GZIPOutputStream; +import java.util.zip.ZipOutputStream; +import java.util.zip.ZipEntry; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static org.testng.Assert.fail; + + +public class CloseDeflaterTest { + + //number of bytes to write + private static final int INPUT_LENGTH= 512; + //OutputStream that will throw an exception during a write operation + private static OutputStream outStream = new OutputStream() { + @Override + public void write(byte[] b, int off, int len) throws IOException { + //throw exception during write + throw new IOException(); + } + @Override + public void write(byte b[]) throws IOException {} + @Override + public void write(int b) throws IOException {} + }; + private static byte[] inputBytes = new byte[INPUT_LENGTH]; + private static Random rand = new Random(); + + @DataProvider(name = "testgzipinput") + public Object[][] testGZipInput() { + //testGZip will close the GZipOutputStream using close() method when the boolean + //useCloseMethod is set to true and finish() method if the value is set to false + return new Object[][] { + { GZIPOutputStream.class, true }, + { GZIPOutputStream.class, false }, + }; + } + + @DataProvider(name = "testzipjarinput") + public Object[][] testZipAndJarInput() { + //testZipAndJarInput will perfrom write/closeEntry operations on JarOutputStream when the boolean + //useJar is set to true and on ZipOutputStream if the value is set to false + return new Object[][] { + { JarOutputStream.class, true }, + { ZipOutputStream.class, false }, + }; + } + + @BeforeTest + public void before_test() + { + //add inputBytes array with random bytes to write into Zip + rand.nextBytes(inputBytes); + } + + //Test for infinite loop by writing bytes to closed GZIPOutputStream + @Test(dataProvider = "testgzipinput") + public void testGZip(Class<?> type, boolean useCloseMethod) throws IOException { + GZIPOutputStream zip = new GZIPOutputStream(outStream); + try { + zip.write(inputBytes, 0, INPUT_LENGTH); + //close zip + if(useCloseMethod) { + zip.close(); + } else { + zip.finish(); + } + } catch (IOException e) { + //expected + } + for (int i = 0; i < 3; i++) { + try { + //write on a closed GZIPOutputStream + zip.write(inputBytes, 0, INPUT_LENGTH); + fail("Deflater closed exception not thrown"); + } catch (NullPointerException e) { + //expected , Deflater has been closed exception + } + } + } + + //Test for infinite loop by writing bytes to closed ZipOutputStream/JarOutputStream + @Test(dataProvider = "testzipjarinput") + public void testZipCloseEntry(Class<?> type,boolean useJar) throws IOException { + ZipOutputStream zip = null; + if(useJar) { + zip = new JarOutputStream(outStream); + } else { + zip = new ZipOutputStream(outStream); + } + try { + zip.putNextEntry(new ZipEntry("")); + } catch (IOException e) { + //expected to throw IOException since putNextEntry calls write method + } + try { + zip.write(inputBytes, 0, INPUT_LENGTH); + //close zip entry + zip.closeEntry(); + } catch (IOException e) { + //expected + } + for (int i = 0; i < 3; i++) { + try { + //write on a closed ZipOutputStream + zip.write(inputBytes, 0, INPUT_LENGTH); + fail("Deflater closed exception not thrown"); + } catch (NullPointerException e) { + //expected , Deflater has been closed exception + } + } + } + +} -- 2.22.0
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2