1 /* 2 * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /** 25 * @test 26 * @bug 8193682 8278794 8284771 27 * @summary Test Infinite loop while writing on closed Deflater and Inflater. 28 * @run testng CloseInflaterDeflaterTest 29 */ 30 package test.java.util.zip; 31 32 import java.io.*; 33 import java.util.Random; 34 import java.util.jar.JarOutputStream; 35 import java.util.zip.DeflaterInputStream; 36 import java.util.zip.DeflaterOutputStream; 37 import java.util.zip.GZIPOutputStream; 38 import java.util.zip.InflaterOutputStream; 39 import java.util.zip.ZipOutputStream; 40 import java.util.zip.ZipEntry; 41 42 import org.testng.annotations.BeforeTest; 43 import org.testng.annotations.DataProvider; 44 import org.testng.annotations.Test; 45 import static org.testng.Assert.assertThrows; 46 47 48 public class CloseInflaterDeflaterTest { 49 50 // Number of bytes to write/read from Deflater/Inflater 51 private static final int INPUT_LENGTH= 512; 52 // OutputStream that will throw an exception during a write operation 53 private static OutputStream outStream = new OutputStream() { 54 @Override 55 public void write(byte[] b, int off, int len) throws IOException { 56 throw new IOException(); 57 } 58 @Override 59 public void write(byte[] b) throws IOException {} 60 @Override 61 public void write(int b) throws IOException {} 62 }; 63 // InputStream that will throw an exception during a read operation 64 private static InputStream inStream = new InputStream() { 65 @Override 66 public int read(byte[] b, int off, int len) throws IOException { 67 throw new IOException(); 68 } 69 @Override 70 public int read(byte[] b) throws IOException { throw new IOException();} 71 @Override 72 public int read() throws IOException { throw new IOException();} 73 }; 74 // Input bytes for read/write operation 75 private static byte[] inputBytes = new byte[INPUT_LENGTH]; 76 // Random function to add bytes to inputBytes 77 private static Random rand = new Random(); 78 79 /** 80 * DataProvider to specify whether to use close() or finish() of OutputStream 81 * 82 * @return Entry object indicating which method to use for closing OutputStream 83 */ 84 @DataProvider testOutputStreams()85 public Object[][] testOutputStreams() { 86 return new Object[][] { 87 { true }, 88 { false }, 89 }; 90 } 91 92 /** 93 * DataProvider to specify on which outputstream closeEntry() has to be called 94 * 95 * @return Entry object returning either JarOutputStream or ZipOutputStream 96 */ 97 @DataProvider testZipAndJar()98 public Object[][] testZipAndJar() throws IOException{ 99 return new Object[][] { 100 { new JarOutputStream(outStream)}, 101 { new ZipOutputStream(outStream)}, 102 }; 103 } 104 105 /** 106 * Add inputBytes array with random bytes to write into OutputStream 107 */ 108 @BeforeTest before_test()109 public void before_test() 110 { 111 rand.nextBytes(inputBytes); 112 } 113 114 /** 115 * Test for infinite loop by writing bytes to closed GZIPOutputStream 116 * 117 * @param useCloseMethod indicates whether to use Close() or finish() method 118 * @throws IOException if an error occurs 119 */ 120 @Test(dataProvider = "testOutputStreams") testGZip(boolean useCloseMethod)121 public void testGZip(boolean useCloseMethod) throws IOException { 122 GZIPOutputStream gzip = new GZIPOutputStream(outStream); 123 gzip.write(inputBytes, 0, INPUT_LENGTH); 124 assertThrows(IOException.class, () -> { 125 // Close GZIPOutputStream 126 if (useCloseMethod) { 127 gzip.close(); 128 } else { 129 gzip.finish(); 130 } 131 }); 132 // Write on a closed GZIPOutputStream, closed Deflater IOException expected 133 assertThrows(NullPointerException.class , () -> gzip.write(inputBytes, 0, INPUT_LENGTH)); 134 } 135 136 /** 137 * Test for infinite loop by writing bytes to closed DeflaterOutputStream 138 * 139 * @param useCloseMethod indicates whether to use Close() or finish() method 140 * @throws IOException if an error occurs 141 */ 142 @Test(dataProvider = "testOutputStreams") testDeflaterOutputStream(boolean useCloseMethod)143 public void testDeflaterOutputStream(boolean useCloseMethod) throws IOException { 144 DeflaterOutputStream def = new DeflaterOutputStream(outStream); 145 assertThrows(IOException.class , () -> def.write(inputBytes, 0, INPUT_LENGTH)); 146 assertThrows(IOException.class, () -> { 147 // Close DeflaterOutputStream 148 if (useCloseMethod) { 149 def.close(); 150 } else { 151 def.finish(); 152 } 153 }); 154 // Write on a closed DeflaterOutputStream, 'Deflater has been closed' NPE is expected 155 assertThrows(NullPointerException.class , () -> def.write(inputBytes, 0, INPUT_LENGTH)); 156 } 157 158 /** 159 * Test for infinite loop by reading bytes from closed DeflaterInputStream 160 * 161 * @throws IOException if an error occurs 162 */ 163 @Test testDeflaterInputStream()164 public void testDeflaterInputStream() throws IOException { 165 DeflaterInputStream def = new DeflaterInputStream(inStream); 166 assertThrows(IOException.class , () -> def.read(inputBytes, 0, INPUT_LENGTH)); 167 // Close DeflaterInputStream 168 def.close(); 169 // Read from a closed DeflaterInputStream, closed Deflater IOException expected 170 assertThrows(IOException.class , () -> def.read(inputBytes, 0, INPUT_LENGTH)); 171 } 172 173 /** 174 * Test for infinite loop by writing bytes to closed InflaterOutputStream 175 * 176 * Note: Disabling this test as it is failing intermittently. 177 * @param useCloseMethod indicates whether to use Close() or finish() method 178 * @throws IOException if an error occurs 179 */ 180 @Test(dataProvider = "testOutputStreams",enabled=false) testInflaterOutputStream(boolean useCloseMethod)181 public void testInflaterOutputStream(boolean useCloseMethod) throws IOException { 182 InflaterOutputStream inf = new InflaterOutputStream(outStream); 183 assertThrows(IOException.class , () -> inf.write(inputBytes, 0, INPUT_LENGTH)); 184 assertThrows(IOException.class , () -> { 185 // Close InflaterOutputStream 186 if (useCloseMethod) { 187 inf.close(); 188 } else { 189 inf.finish(); 190 } 191 }); 192 // Write on a closed InflaterOutputStream , closed Inflater IOException expected 193 assertThrows(IOException.class , () -> inf.write(inputBytes, 0, INPUT_LENGTH)); 194 } 195 196 /** 197 * Test for infinite loop by writing bytes to closed ZipOutputStream/JarOutputStream 198 * 199 * @param zip will be the instance of either JarOutputStream or ZipOutputStream 200 * @throws IOException if an error occurs 201 */ 202 @Test(dataProvider = "testZipAndJar") testZipCloseEntry(ZipOutputStream zip)203 public void testZipCloseEntry(ZipOutputStream zip) throws IOException { 204 assertThrows(IOException.class , () -> zip.putNextEntry(new ZipEntry(""))); 205 zip.write(inputBytes, 0, INPUT_LENGTH); 206 assertThrows(IOException.class , () -> zip.closeEntry()); 207 // Write on a closed ZipOutputStream , 'Deflater has been closed' NPE is expected 208 assertThrows(NullPointerException.class , () -> zip.write(inputBytes, 0, INPUT_LENGTH)); 209 } 210 211 } 212