# HG changeset patch # User vromero # Date 1356103675 0 # Node ID 391288e42c6735664c7e1b5eb41f92982e1e8908 # Parent 974d4423c999f78d4c0c6656102a7e08913b30ac 8003512: javac doesn't work with jar files with >64k entries Reviewed-by: jjg, ksrini Contributed-by: martinrb@google.com diff -r 974d4423c999 -r 391288e42c67 langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndex.java --- a/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndex.java Fri Dec 21 08:45:43 2012 -0800 +++ b/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndex.java Fri Dec 21 15:27:55 2012 +0000 @@ -548,17 +548,15 @@ } if (i >= 0) { - zipDir = new byte[get4ByteLittleEndian(endbuf, i + 12) + 2]; - zipDir[0] = endbuf[i + 10]; - zipDir[1] = endbuf[i + 11]; + zipDir = new byte[get4ByteLittleEndian(endbuf, i + 12)]; int sz = get4ByteLittleEndian(endbuf, i + 16); // a negative offset or the entries field indicates a // potential zip64 archive - if (sz < 0 || get2ByteLittleEndian(zipDir, 0) == 0xffff) { + if (sz < 0 || get2ByteLittleEndian(endbuf, i + 10) == 0xffff) { throw new ZipFormatException("detected a zip64 archive"); } zipRandomFile.seek(start + sz); - zipRandomFile.readFully(zipDir, 2, zipDir.length - 2); + zipRandomFile.readFully(zipDir, 0, zipDir.length); return; } else { endbufend = endbufpos + 21; @@ -568,14 +566,13 @@ } private void buildIndex() throws IOException { - int entryCount = get2ByteLittleEndian(zipDir, 0); + int len = zipDir.length; // Add each of the files - if (entryCount > 0) { + if (len > 0) { directories = new LinkedHashMap(); ArrayList entryList = new ArrayList(); - int pos = 2; - for (int i = 0; i < entryCount; i++) { + for (int pos = 0; pos < len; ) { pos = readEntry(pos, entryList, directories); } diff -r 974d4423c999 -r 391288e42c67 langtools/test/tools/javac/file/zip/8003512/LoadClassFromJava6CreatedJarTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/langtools/test/tools/javac/file/zip/8003512/LoadClassFromJava6CreatedJarTest.java Fri Dec 21 15:27:55 2012 +0000 @@ -0,0 +1,183 @@ + +/* + * Copyright (c) 2002, 2012, 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 8003512 + * @summary javac doesn't work with jar files with >64k entries + * @compile -target 6 -source 6 -XDignore.symbol.file LoadClassFromJava6CreatedJarTest.java ../Utils.java + * @run main/timeout=360 LoadClassFromJava6CreatedJarTest + */ + +/* + * The test creates a jar file with more than 64K entries. The jar file is + * created executing the LoadClassFromJava6CreatedJarTest$MakeJar + * class with a JVM version 6. The test must include Java 6 features only. + * + * The aim is to verify classes included in jar files with more than 64K entries + * created with Java 6 can be loaded by more recent versions of Java. + * + * A path to JDK or JRE version 6 is needed. This can be provided + * by passing this option to jtreg: + * -javaoption:-Djava6.home="/path/to/jdk_or_jre6" + */ + +import java.io.BufferedInputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Arrays; +import java.util.List; +import java.util.zip.CRC32; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +public class LoadClassFromJava6CreatedJarTest { + + static final String javaHome6 = System.getProperty("java6.home"); + static final String testClasses = System.getProperty("test.classes"); + + public static void main(String... args) + throws IOException, InterruptedException { + if (javaHome6 != null) { + new LoadClassFromJava6CreatedJarTest().run(); + } else { + System.out.println( + "The test LoadClassFromJava6CreatedJarTest cannot be executed. " + + "In order to run it you should pass an option with " + + "this form -javaoption:-Djava6.home=\"/path/to/jdk_or_jre6\" " + + "to jtreg."); + } + } + + void run() throws IOException, InterruptedException { + File classA = new File("A.java"); + Utils.createJavaFile(classA, null); + if (!Utils.compile("-target", "6", "-source", "6", + classA.getAbsolutePath())) { + throw new AssertionError("Test failed while compiling class A"); + } + + executeCommand(Arrays.asList(javaHome6 + "/bin/java", "-classpath", + testClasses, "LoadClassFromJava6CreatedJarTest$MakeJar")); + + File classB = new File("B.java"); + Utils.createJavaFile(classB, classA); + if (!Utils.compile("-cp", "a.jar", classB.getAbsolutePath())) { + throw new AssertionError("Test failed while compiling class Main"); + } + } + + void executeCommand(List command) + throws IOException, InterruptedException { + ProcessBuilder pb = new ProcessBuilder(command). + redirectErrorStream(true); + Process p = pb.start(); + BufferedReader r = + new BufferedReader(new InputStreamReader(p.getInputStream())); + String line; + while ((line = r.readLine()) != null) { + System.err.println(line); + } + int rc = p.waitFor(); + if (rc != 0) { + throw new AssertionError("Unexpected exit code: " + rc); + } + } + + static class MakeJar { + public static void main(String[] args) throws Throwable { + File classFile = new File("A.class"); + ZipOutputStream zos = null; + FileInputStream fis = null; + final int MAX = Short.MAX_VALUE * 2 + 10; + ZipEntry ze = null; + try { + zos = new ZipOutputStream(new FileOutputStream("a.jar")); + zos.setLevel(ZipOutputStream.STORED); + zos.setMethod(ZipOutputStream.STORED); + for (int i = 0; i < MAX ; i++) { + ze = new ZipEntry("X" + i + ".txt"); + ze.setSize(0); + ze.setCompressedSize(0); + ze.setCrc(0); + zos.putNextEntry(ze); + } + + // add a class file + ze = new ZipEntry("A.class"); + ze.setCompressedSize(classFile.length()); + ze.setSize(classFile.length()); + ze.setCrc(computeCRC(classFile)); + zos.putNextEntry(ze); + fis = new FileInputStream(classFile); + for (int c; (c = fis.read()) >= 0;) { + zos.write(c); + } + } finally { + zos.close(); + fis.close(); + } + } + + private static final int BUFFER_LEN = Short.MAX_VALUE * 2; + + static long getCount(long minlength) { + return (minlength / BUFFER_LEN) + 1; + } + + static long computeCRC(long minlength) { + CRC32 crc = new CRC32(); + byte[] buffer = new byte[BUFFER_LEN]; + long count = getCount(minlength); + for (long i = 0; i < count; i++) { + crc.update(buffer); + } + return crc.getValue(); + } + + static long computeCRC(File inFile) throws IOException { + byte[] buffer = new byte[8192]; + CRC32 crc = new CRC32(); + FileInputStream fis = null; + BufferedInputStream bis = null; + try { + fis = new FileInputStream(inFile); + bis = new BufferedInputStream(fis); + int n = bis.read(buffer); + while (n > 0) { + crc.update(buffer, 0, n); + n = bis.read(buffer); + } + } finally { + bis.close(); + fis.close(); + } + return crc.getValue(); + } + } +} diff -r 974d4423c999 -r 391288e42c67 langtools/test/tools/javac/file/zip/Utils.java --- a/langtools/test/tools/javac/file/zip/Utils.java Fri Dec 21 08:45:43 2012 -0800 +++ b/langtools/test/tools/javac/file/zip/Utils.java Fri Dec 21 15:27:55 2012 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -21,6 +21,12 @@ * questions. */ +/* + * This utils class is been used by test T8003512 which is compiled with Java 6 + * only features. So if this class is modified, it should be so using Java 6 + * features only. + */ + import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.Closeable;