JDK-7002855 : reading a .class resource from jar input stream does not work with jdk7 b116
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util.jar
  • Affected Version: 7
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: linux_ubuntu
  • CPU: x86
  • Submitted: 2010-11-25
  • Updated: 2011-04-04
  • Resolved: 2011-04-04
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 7
7Resolved
Related Reports
Duplicate :  
Relates :  
Description
The following code reads and prints as expected with jdk6 1.6.0_22. But, this prints all zeros with jdk7 b119. This was run on Ubuntu 10.04.

File: Test.java

import java.io.*;

public class Test {
  public static void main(String[] args) throws Exception {
      InputStream is = Test.class.getResourceAsStream("Test.class");
      System.out.println(is);
      byte[] header = new byte[8];
      is.read(header);
      for (byte b : header) {
            System.out.println(b);
      }
      int minor = (header[4] << 8) | header[5];
      int major = (header[6] << 8) | header[7];
      System.out.println("minor " + minor);
      System.out.println("major " + major);
  }
}

Steps to reproduce:

1) java Test.java
2) jar cvf test.jar Test.class
3) java -cp test.jar Test

With jdk7, I got the following result:


$ ~/bin/jdk1.7.0/bin/java -cp test.jar Test
sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@117a8bd
-54
0
0
0
0
0
0
0
minor 0
major 0

With jdk6, I get the following result:

$ java -cp test.jar Test
sun.net.www.protocol.jar.JarURLConnection$JarURLInputStream@1690726
-54
-2
-70
-66
0
0
0
50
minor 0
major 50
If a println is added,

    System.out.println(is.read(header));

instead of

    is.read(header)

then the test works as expected even with jdk7 b119.

This does suggest it *may* be a JVM issue.

Comments
EVALUATION The change just putback for #6751338 backs out all the change we made for 6975829 (which is the direct trigger of this regression). Verified the regression is no longer reproducible against the binary with the changet for #6751338. Closed this one as the dup of #6751338.
04-04-2011

EVALUATION Two issues here. (1) The fix for #6975829 uses "len + 20" as the buffering size, but it appears the "20" is not big enough (the test shows the magic number is 22) (2) The test case uses is.read(header) to read data without verifying the return value (number of bytes read), InputStream.read() obviously does not guarantee this invocation always fill the buffer fully, try something like below int n = 0; int off = 0; while (off < header.length && (n = is.read(header, off, header.length - off)) >= 0) { off += n; } should solve the problem. Need to re-visit the fix for #6975829
30-11-2010

EVALUATION I noticed some strangeness when running the test. Small irrelevant modifications in the test sometimes lead to 8 bytes being read. I think this, and the addition of println, cause the test byte code to be a different size, and therefore the test.jar will be a different size. Leading to the perceived difference in behavior. I don't think its got anything to do with System.out. Inflater is a bit unpredictable in this way.
26-11-2010

EVALUATION As I said earlier, adding a println around is.read(header) call "fixes" the issue with jdk7. But, if I save the return value from read in a local variable and print it, it does not work! import java.io.*; public class Test { public static void main(String[] args) throws Exception { InputStream is = Test.class.getResourceAsStream("Test.class"); System.out.println(is); byte[] header = new byte[8]; int x = is.read(header); System.out.println("x = " + x); for (byte b : header) { System.out.println(b); } int minor = (header[4] << 8) | header[5]; int major = (header[6] << 8) | header[7]; System.out.println("minor " + minor); System.out.println("major " + major); } } With jdk6, "x = 8" is printed as expected. With jdk7, "x = 1" is printed!
26-11-2010

EVALUATION The change for 6975829: "Perf. of gzip in existing JDKs is too slower than in 1.3.1", appears to cause the short read.
25-11-2010

EVALUATION The test appears to have a bug in that it doesn't check the return from read and so can't handle short reads. That said, it's not immediately obvious why you would get a short read here.
25-11-2010