8003512: javac doesn't work with jar files with >64k entries

Fri, 21 Dec 2012 15:27:55 +0000

author
vromero
date
Fri, 21 Dec 2012 15:27:55 +0000
changeset 1467
189b26e3818f
parent 1466
b52a38d4536c
child 1468
690c41cdab55

8003512: javac doesn't work with jar files with >64k entries
Reviewed-by: jjg, ksrini
Contributed-by: martinrb@google.com

src/share/classes/com/sun/tools/javac/file/ZipFileIndex.java file | annotate | diff | comparison | revisions
test/tools/javac/file/zip/8003512/LoadClassFromJava6CreatedJarTest.java file | annotate | diff | comparison | revisions
test/tools/javac/file/zip/Utils.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/classes/com/sun/tools/javac/file/ZipFileIndex.java	Fri Dec 21 08:45:43 2012 -0800
     1.2 +++ b/src/share/classes/com/sun/tools/javac/file/ZipFileIndex.java	Fri Dec 21 15:27:55 2012 +0000
     1.3 @@ -548,17 +548,15 @@
     1.4                  }
     1.5  
     1.6                  if (i >= 0) {
     1.7 -                    zipDir = new byte[get4ByteLittleEndian(endbuf, i + 12) + 2];
     1.8 -                    zipDir[0] = endbuf[i + 10];
     1.9 -                    zipDir[1] = endbuf[i + 11];
    1.10 +                    zipDir = new byte[get4ByteLittleEndian(endbuf, i + 12)];
    1.11                      int sz = get4ByteLittleEndian(endbuf, i + 16);
    1.12                      // a negative offset or the entries field indicates a
    1.13                      // potential zip64 archive
    1.14 -                    if (sz < 0 || get2ByteLittleEndian(zipDir, 0) == 0xffff) {
    1.15 +                    if (sz < 0 || get2ByteLittleEndian(endbuf, i + 10) == 0xffff) {
    1.16                          throw new ZipFormatException("detected a zip64 archive");
    1.17                      }
    1.18                      zipRandomFile.seek(start + sz);
    1.19 -                    zipRandomFile.readFully(zipDir, 2, zipDir.length - 2);
    1.20 +                    zipRandomFile.readFully(zipDir, 0, zipDir.length);
    1.21                      return;
    1.22                  } else {
    1.23                      endbufend = endbufpos + 21;
    1.24 @@ -568,14 +566,13 @@
    1.25          }
    1.26  
    1.27          private void buildIndex() throws IOException {
    1.28 -            int entryCount = get2ByteLittleEndian(zipDir, 0);
    1.29 +            int len = zipDir.length;
    1.30  
    1.31              // Add each of the files
    1.32 -            if (entryCount > 0) {
    1.33 +            if (len > 0) {
    1.34                  directories = new LinkedHashMap<RelativeDirectory, DirectoryEntry>();
    1.35                  ArrayList<Entry> entryList = new ArrayList<Entry>();
    1.36 -                int pos = 2;
    1.37 -                for (int i = 0; i < entryCount; i++) {
    1.38 +                for (int pos = 0; pos < len; ) {
    1.39                      pos = readEntry(pos, entryList, directories);
    1.40                  }
    1.41  
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/test/tools/javac/file/zip/8003512/LoadClassFromJava6CreatedJarTest.java	Fri Dec 21 15:27:55 2012 +0000
     2.3 @@ -0,0 +1,183 @@
     2.4 +
     2.5 +/*
     2.6 + * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
     2.7 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     2.8 + *
     2.9 + * This code is free software; you can redistribute it and/or modify it
    2.10 + * under the terms of the GNU General Public License version 2 only, as
    2.11 + * published by the Free Software Foundation.
    2.12 + *
    2.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
    2.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    2.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    2.16 + * version 2 for more details (a copy is included in the LICENSE file that
    2.17 + * accompanied this code).
    2.18 + *
    2.19 + * You should have received a copy of the GNU General Public License version
    2.20 + * 2 along with this work; if not, write to the Free Software Foundation,
    2.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    2.22 + *
    2.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    2.24 + * or visit www.oracle.com if you need additional information or have any
    2.25 + * questions.
    2.26 + */
    2.27 +
    2.28 +/*
    2.29 + * @test
    2.30 + * @bug 8003512
    2.31 + * @summary javac doesn't work with jar files with >64k entries
    2.32 + * @compile -target 6 -source 6 -XDignore.symbol.file LoadClassFromJava6CreatedJarTest.java ../Utils.java
    2.33 + * @run main/timeout=360 LoadClassFromJava6CreatedJarTest
    2.34 + */
    2.35 +
    2.36 +/*
    2.37 + * The test creates a jar file with more than 64K entries. The jar file is
    2.38 + * created executing the LoadClassFromJava6CreatedJarTest$MakeJar
    2.39 + * class with a JVM version 6. The test must include Java 6 features only.
    2.40 + *
    2.41 + * The aim is to verify classes included in jar files with more than 64K entries
    2.42 + * created with Java 6 can be loaded by more recent versions of Java.
    2.43 + *
    2.44 + * A path to JDK or JRE version 6 is needed. This can be provided
    2.45 + * by passing this option to jtreg:
    2.46 + * -javaoption:-Djava6.home="/path/to/jdk_or_jre6"
    2.47 + */
    2.48 +
    2.49 +import java.io.BufferedInputStream;
    2.50 +import java.io.BufferedReader;
    2.51 +import java.io.File;
    2.52 +import java.io.FileInputStream;
    2.53 +import java.io.FileOutputStream;
    2.54 +import java.io.IOException;
    2.55 +import java.io.InputStreamReader;
    2.56 +import java.util.Arrays;
    2.57 +import java.util.List;
    2.58 +import java.util.zip.CRC32;
    2.59 +import java.util.zip.ZipEntry;
    2.60 +import java.util.zip.ZipOutputStream;
    2.61 +
    2.62 +public class LoadClassFromJava6CreatedJarTest {
    2.63 +
    2.64 +    static final String javaHome6 = System.getProperty("java6.home");
    2.65 +    static final String testClasses = System.getProperty("test.classes");
    2.66 +
    2.67 +    public static void main(String... args)
    2.68 +            throws IOException, InterruptedException {
    2.69 +        if (javaHome6 != null) {
    2.70 +            new LoadClassFromJava6CreatedJarTest().run();
    2.71 +        } else {
    2.72 +            System.out.println(
    2.73 +                "The test LoadClassFromJava6CreatedJarTest cannot be executed. " +
    2.74 +                "In order to run it you should pass an option with " +
    2.75 +                "this form -javaoption:-Djava6.home=\"/path/to/jdk_or_jre6\" " +
    2.76 +                "to jtreg.");
    2.77 +        }
    2.78 +    }
    2.79 +
    2.80 +    void run() throws IOException, InterruptedException {
    2.81 +        File classA = new File("A.java");
    2.82 +        Utils.createJavaFile(classA, null);
    2.83 +        if (!Utils.compile("-target", "6", "-source", "6",
    2.84 +            classA.getAbsolutePath())) {
    2.85 +            throw new AssertionError("Test failed while compiling class A");
    2.86 +        }
    2.87 +
    2.88 +        executeCommand(Arrays.asList(javaHome6 + "/bin/java", "-classpath",
    2.89 +            testClasses, "LoadClassFromJava6CreatedJarTest$MakeJar"));
    2.90 +
    2.91 +        File classB = new File("B.java");
    2.92 +        Utils.createJavaFile(classB, classA);
    2.93 +        if (!Utils.compile("-cp", "a.jar", classB.getAbsolutePath())) {
    2.94 +            throw new AssertionError("Test failed while compiling class Main");
    2.95 +        }
    2.96 +    }
    2.97 +
    2.98 +    void executeCommand(List<String> command)
    2.99 +            throws IOException, InterruptedException {
   2.100 +        ProcessBuilder pb = new ProcessBuilder(command).
   2.101 +            redirectErrorStream(true);
   2.102 +        Process p = pb.start();
   2.103 +        BufferedReader r =
   2.104 +            new BufferedReader(new InputStreamReader(p.getInputStream()));
   2.105 +        String line;
   2.106 +        while ((line = r.readLine()) != null) {
   2.107 +            System.err.println(line);
   2.108 +        }
   2.109 +        int rc = p.waitFor();
   2.110 +        if (rc != 0) {
   2.111 +            throw new AssertionError("Unexpected exit code: " + rc);
   2.112 +        }
   2.113 +    }
   2.114 +
   2.115 +    static class MakeJar {
   2.116 +        public static void main(String[] args) throws Throwable {
   2.117 +            File classFile = new File("A.class");
   2.118 +            ZipOutputStream zos = null;
   2.119 +            FileInputStream fis = null;
   2.120 +            final int MAX = Short.MAX_VALUE * 2 + 10;
   2.121 +            ZipEntry ze = null;
   2.122 +            try {
   2.123 +                zos = new ZipOutputStream(new FileOutputStream("a.jar"));
   2.124 +                zos.setLevel(ZipOutputStream.STORED);
   2.125 +                zos.setMethod(ZipOutputStream.STORED);
   2.126 +                for (int i = 0; i < MAX ; i++) {
   2.127 +                    ze = new ZipEntry("X" + i + ".txt");
   2.128 +                    ze.setSize(0);
   2.129 +                    ze.setCompressedSize(0);
   2.130 +                    ze.setCrc(0);
   2.131 +                    zos.putNextEntry(ze);
   2.132 +                }
   2.133 +
   2.134 +                // add a class file
   2.135 +                ze = new ZipEntry("A.class");
   2.136 +                ze.setCompressedSize(classFile.length());
   2.137 +                ze.setSize(classFile.length());
   2.138 +                ze.setCrc(computeCRC(classFile));
   2.139 +                zos.putNextEntry(ze);
   2.140 +                fis = new FileInputStream(classFile);
   2.141 +                for (int c; (c = fis.read()) >= 0;) {
   2.142 +                    zos.write(c);
   2.143 +                }
   2.144 +            } finally {
   2.145 +                zos.close();
   2.146 +                fis.close();
   2.147 +            }
   2.148 +        }
   2.149 +
   2.150 +        private static final int BUFFER_LEN = Short.MAX_VALUE * 2;
   2.151 +
   2.152 +        static long getCount(long minlength) {
   2.153 +            return (minlength / BUFFER_LEN) + 1;
   2.154 +        }
   2.155 +
   2.156 +        static long computeCRC(long minlength) {
   2.157 +            CRC32 crc = new CRC32();
   2.158 +            byte[] buffer = new byte[BUFFER_LEN];
   2.159 +            long count = getCount(minlength);
   2.160 +            for (long i = 0; i < count; i++) {
   2.161 +                crc.update(buffer);
   2.162 +            }
   2.163 +            return crc.getValue();
   2.164 +        }
   2.165 +
   2.166 +        static long computeCRC(File inFile) throws IOException {
   2.167 +            byte[] buffer = new byte[8192];
   2.168 +            CRC32 crc = new CRC32();
   2.169 +            FileInputStream fis = null;
   2.170 +            BufferedInputStream bis = null;
   2.171 +            try {
   2.172 +                fis = new FileInputStream(inFile);
   2.173 +                bis = new BufferedInputStream(fis);
   2.174 +                int n = bis.read(buffer);
   2.175 +                while (n > 0) {
   2.176 +                    crc.update(buffer, 0, n);
   2.177 +                    n = bis.read(buffer);
   2.178 +                }
   2.179 +            } finally {
   2.180 +                bis.close();
   2.181 +                fis.close();
   2.182 +            }
   2.183 +            return crc.getValue();
   2.184 +        }
   2.185 +    }
   2.186 +}
     3.1 --- a/test/tools/javac/file/zip/Utils.java	Fri Dec 21 08:45:43 2012 -0800
     3.2 +++ b/test/tools/javac/file/zip/Utils.java	Fri Dec 21 15:27:55 2012 +0000
     3.3 @@ -1,5 +1,5 @@
     3.4  /*
     3.5 - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
     3.6 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
     3.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3.8   *
     3.9   * This code is free software; you can redistribute it and/or modify it
    3.10 @@ -21,6 +21,12 @@
    3.11   * questions.
    3.12   */
    3.13  
    3.14 +/*
    3.15 + * This utils class is been used by test T8003512 which is compiled with Java 6
    3.16 + * only features. So if this class is modified, it should be so using Java 6
    3.17 + * features only.
    3.18 + */
    3.19 +
    3.20  import java.io.BufferedInputStream;
    3.21  import java.io.BufferedOutputStream;
    3.22  import java.io.Closeable;

mercurial