1 /* 2 * Copyright (c) 2015, 2017, 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 /* @test 25 * @bug 6907252 26 * @summary ZipFileInputStream Not Thread-Safe 27 * @library /test/lib 28 * @build jdk.test.lib.Platform 29 * jdk.test.lib.Utils 30 * jdk.test.lib.Asserts 31 * jdk.test.lib.JDKToolFinder 32 * jdk.test.lib.JDKToolLauncher 33 * jdk.test.lib.process.* 34 * jdk.test.lib.util.FileUtils 35 * @run main ZipEntryFreeTest 36 */ 37 38 import java.io.*; 39 import java.nio.file.Paths; 40 import java.util.Random; 41 import java.util.Timer; 42 import java.util.TimerTask; 43 import java.util.zip.*; 44 import jdk.test.lib.util.FileUtils; 45 46 public class ZipEntryFreeTest extends Thread { 47 48 private static final int NUM_THREADS = 5; 49 private static final int TEST_ITERATIONS = 5; 50 private static final String ZIPFILE_NAME = "large.zip"; 51 private static final String ZIPENTRY_NAME = "random.txt"; 52 private static InputStream is = null; 53 final Timer timer = new Timer(); 54 55 public static void main(String args[]) throws Exception { 56 createZipFile(); 57 try { 58 for (int i = 0; i < TEST_ITERATIONS; i++) { 59 runTest(); 60 } 61 } finally { 62 FileUtils.deleteFileIfExistsWithRetry(Paths.get(ZIPFILE_NAME)); 63 } 64 } 65 66 private static void runTest() throws Exception { 67 try (ZipFile zf = new ZipFile(new File(ZIPFILE_NAME))) { 68 is = zf.getInputStream(zf.getEntry(ZIPENTRY_NAME + "_0")); 69 Thread[] threadArray = new Thread[NUM_THREADS]; 70 for (int i = 0; i < threadArray.length; i++) { 71 threadArray[i] = new ZipEntryFreeTest(); 72 } 73 for (int i = 0; i < threadArray.length; i++) { 74 threadArray[i].start(); 75 } 76 for (int i = 0; i < threadArray.length; i++) { 77 threadArray[i].join(); 78 } 79 } 80 } 81 82 private static void createZipFile() throws Exception { 83 Random rnd = new Random(1000L); 84 byte[] contents = new byte[2_000_000]; 85 ZipEntry ze = null; 86 87 try (ZipOutputStream zos = 88 new ZipOutputStream(new FileOutputStream(ZIPFILE_NAME))) { 89 // uncompressed mode seemed to tickle the crash 90 zos.setMethod(ZipOutputStream.STORED); 91 for (int ze_count = 0; ze_count < 10; ze_count++) { 92 rnd.nextBytes(contents); 93 ze = createZipEntry(contents, ze_count); 94 zos.putNextEntry(ze); 95 zos.write(contents, 0, contents.length); 96 } 97 zos.flush(); 98 } 99 } 100 101 private static ZipEntry createZipEntry(byte[] b, int i) { 102 ZipEntry ze = new ZipEntry(ZIPENTRY_NAME + "_" + i); 103 ze.setCompressedSize(b.length); 104 ze.setSize(b.length); 105 CRC32 crc = new CRC32(); 106 crc.update(b); 107 ze.setCrc(crc.getValue()); 108 return ze; 109 } 110 111 @Override 112 public void run() { 113 try { 114 int iteration = 0; 115 TimerTask tt = (new TimerTask() { 116 @Override 117 public void run() { 118 try { 119 is.close(); 120 } catch (Exception ex) { 121 ex.printStackTrace(System.out); 122 } 123 } 124 }); 125 timer.schedule(tt, 50); 126 while (is.read() != -1 && iteration++ < 1_000) { } 127 } catch (ZipException ze) { 128 // ZipException now expected instead of ZIP_Read crash 129 System.out.println(ze); 130 } catch (Exception e) { 131 throw new RuntimeException(e); 132 } finally { 133 timer.cancel(); 134 } 135 } 136 }