JDK-6278051 : ClassLoader.getSystemResourceAsStream -- read method behavior change
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.io
  • Affected Version: 5.0
  • Priority: P3
  • Status: Closed
  • Resolution: Not an Issue
  • OS: windows_nt,windows_xp
  • CPU: x86
  • Submitted: 2005-05-31
  • Updated: 2011-02-16
  • Resolved: 2005-07-14
Related Reports
Duplicate :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.5.0_03"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_03-b07)
Java HotSpot(TM) Client VM (build 1.5.0_03-b07, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Window NT 4.00.1381

A DESCRIPTION OF THE PROBLEM :
ClassLoader.getSystemResourceAsStream -- lost last a few bytes for binary file that is packed in JAR file (with compressed).

our product puts a public key file in the product Jar files to verify digital signature. this product is compiled by JDK 1.3.0_02 and JDK 1.4.2_07 and put into several JAR files with ZIP compression. it runs fine on Windows, Solaris, Linux and HP-UX with different JDK and JRE. after we install the JDK 1.5 in our Window NT workstation, the verify always failed even if we recompile it with JDK 1.5 and re-jar it. we debug our code, we found the inputstream that is generated by ClassLoader.getSystemResourceAsStream can not properly read the public key file. so we re-jar file with -0 "store only" option, every things work great.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1) Compile the java file.
2) jar cvfm test.jar mymanifest.txt com/mbf/license/properties/mykey.pub com/mbf/license/testmain.class
3) java -jar test.jar

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
MBFVerSCAT1 encKey.length = 443 rtn = 443
308201B73082012C06072A8648CE3804013082011F02818100FD7F53811D75122952DF4A9C2EECE4E7F611B7523CEF4400C31E3F80B6512669455D402251FB59
3D8D58FABFC5F5BA30F6CB9B556CD7813B801D346FF26660B76B9950A5A49F9FE8047B1022C24FBBA9D7FEB7C61BF83B57E7C6A8A6150F04FB83F6D3C51EC302
3554135A169132F675F3AE2B61D72AEFF22203199DD14801C70215009760508F15230BCCB292B982A2EB840BF0581CF502818100F7E1A085D69B3DDECBBCAB5C
36B857B97994AFBBFA3AEA82F9574C0B3D0782675159578EBAD4594FE67107108180B449167123E84C281613B7CF09328CC8A6E13C167A8B547C8D28E0A3AE1E
2BB3A675916EA37F0BFA213562F1FB627A01243BCCA4F1BEA8519089A883DFE15AE59F06928B665E807B552564014C3BFECF492A03818400028180503C460655
F7C833227F52361BFA117D6D2D1033A91ACEF6D9D9B035AD97A4D5F52FA5737827FA671A88CE10BF7839780EF6496033C5595DAFC14794F180B68D87A1449D13
7911A5979510EF9C6AB2707624D9AF66E5F920939099D125F7CBF99C4D291F09B90378357345B5681D870C09BC49D657DBFA9DAE39D5C1D38DEC8D

ACTUAL -
MBFVerSCAT1 encKey.length = 443 rtn = 438
308201B73082012C06072A8648CE3804013082011F02818100FD7F53811D75122952DF4A9C2EECE4E7F611B7523CEF4400C31E3F80B6512669455D402251FB59
3D8D58FABFC5F5BA30F6CB9B556CD7813B801D346FF26660B76B9950A5A49F9FE8047B1022C24FBBA9D7FEB7C61BF83B57E7C6A8A6150F04FB83F6D3C51EC302
3554135A169132F675F3AE2B61D72AEFF22203199DD14801C70215009760508F15230BCCB292B982A2EB840BF0581CF502818100F7E1A085D69B3DDECBBCAB5C
36B857B97994AFBBFA3AEA82F9574C0B3D0782675159578EBAD4594FE67107108180B449167123E84C281613B7CF09328CC8A6E13C167A8B547C8D28E0A3AE1E
2BB3A675916EA37F0BFA213562F1FB627A01243BCCA4F1BEA8519089A883DFE15AE59F06928B665E807B552564014C3BFECF492A03818400028180503C460655
F7C833227F52361BFA117D6D2D1033A91ACEF6D9D9B035AD97A4D5F52FA5737827FA671A88CE10BF7839780EF6496033C5595DAFC14794F180B68D87A1449D13
7911A5979510EF9C6AB2707624D9AF66E5F920939099D125F7CBF99C4D291F09B90378357345B5681D870C09BC49D657DBFA9DAE39D50000000000


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package com.mbf.license;

import java.util.*;
import java.io.*;

public class testmain {
	
	public testmain() throws Exception {
		String keyname = "com/mbf/license/properties/mykey.pub";
		InputStream keyfis = ClassLoader.getSystemResourceAsStream(keyname);
		byte[] encKey = new byte[keyfis.available()];
		int rtn = keyfis.read(encKey);
		keyfis.close();
		System.out.println("MBFVerSCAT1 encKey.length = " + encKey.length + " rtn = " + rtn);
		System.out.println(asHex(encKey));
	}
	
  private String asHex (byte hash[]) {
    StringBuffer buf = new StringBuffer(hash.length * 2);

    for (int i = 0; i < hash.length; i++) {
      if (((int) hash[i] & 0xff) < 0x10)
         buf.append("0");
      buf.append(Long.toString((int) hash[i] & 0xff, 16));
    }

    return buf.toString().toUpperCase();
  }

	public static void main(String[] args) throws Exception {
		testmain tm = new testmain();
	}
}

PS
you can reverse the debug output and put them into a file, then put it into a jar
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
we have changed the JAR option

jar -cvf0m ...

Release Regression From : 1.4.2_07
The above release value was the last known release where this 
bug was known to work. Since then there has been a regression.
###@###.### 2005-05-31 08:32:31 GMT

Comments
EVALUATION This is not a defect. The program failure is caused by dependence on implementation details. The bytes are not "lost" but were simply not retrieved by the first invocation of read. The javadoc summary line for InputStream.read(byte[],int,int) is the final word with respect to stream behavior relevant to this CR: "Reads up to len bytes of data from the input stream into an array of bytes." Application code can never rely on a single read returning the same number of bytes reported by available(). As of Mustang build 14, the stream implementation for compressed jar files changed such that a single invocation of the above read method only reads a portion of the requested bytes in some cases. If the code submitted with this CR is modified to invoke available() a second time the remainder reflected by the difference between the original available count and the count returned by the first read will be returned. The remaining bytes can then be retrieved with additional invocations of one of the read methods. However, the current doc for the available() method of the java.io stream classes is not as clear as it could be and it's easy to see how misunderstandings can come about. The doc for this method is being improved with change request 4711604. ###@###.### 2005-07-14 17:05:39 GMT
14-07-2005