JDK-6934615 : Relative classpaths in jarfile manifests are handled inefficiently by rmic
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.rmi
  • Affected Version: 6u18
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2010-03-12
  • Updated: 2010-06-09
  • Resolved: 2010-06-09
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 Other
7 b97Fixed OpenJDK6Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Description
OPERATING SYSTEM
----------------
All.

FULL JDK VERSION(S)
-------------------
JDK 1.5.0_11
JDK 1.6.0_01
JDK 7b93

DESCRIPTION
-----------
CR 647331 introduced the ability for rmic to handle relative manifest classpaths.

The paths are not canonicalised, so you can end up with huge paths where the majority
is redundant. This causes problems when the path is converted to a String (within the
rmic code).

For example, create a file structure where you have several jarfiles in ".", and several more in "./lib", and setup the manifest classpaths so that the jarfiles in "." point to jarfiles in "./lib", and the jarfiles in "./lib" point to the jarfiles in "." (using ".."). e.g.:

Classpath attribute for jarfile "test1.jar" in ".":

----
Class-Path: lib/testlib2.jar lib/testlib3.jar lib/testlib4.jar lib/testlib5.jar lib/testlib6.jar lib/testlib7.jar lib/testlib8.jar lib/testlib9.jar lib/testlib10.jar
----

Classpath attribute for jarfile "testlib1.jar" in "./lib":

----
Class-Path: ../test2.jar ../test3.jar ../test4.jar ../test5.jar ../test6.jar ../test7.jar ../test8.jar ../test9.jar ../test10.jar
----

If you create similar classpaths in each of the other jarfiles, rmic will end up adding paths like this to its classpath:

lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\..\lib\testlib1.jar

In a test situation with 10 jarfiles in ".", each of which refers to 9 jarfiles in "./lib", and vice versa, rmic will add a total of over 25000 jarfile paths to its classpath, even though only 20 jarfiles really need to be added.

In real world situations this can cause rmic to take an unnecessarily large amount of time to run
or it can cause OutOfMemoryErrors when trying to create the classpath String.

The problem occurs with JDK 1.5.0_11, but it is much more pronounced with Java 6/7 because of the changes to the way manifest classpaths are processed. For instance, with the example above, 5.0
only creates 5400 paths rather than 25000.

Javac encountered similar issues - 4212732 (10-Fix Delivered), 6400872 (10-Fix Delivered) and 6485027.

STEPS TO REPRODUCE:
A Java Licensee has provided us with a testcase.  The testcase is self-contained, for the most part,
but requires specific setup and execution.  Testcase can be obtained from Licensee Engineering.

SUGGESTED FIX:
See Suggested Fix section.

Comments
EVALUATION Despite the potential for better long term solutions, the best short term solution is simply to use getCanonicalPath() to normalize the result of new File(jarParent, elt), since this is the simplest fix to backport to 6 and 5.
24-05-2010

EVALUATION The code in question is in a nested class, Path, which has the following comment: /** * Utility for building paths of directories and JAR files. This * class was copied from com.sun.tools.javac.util.Paths as part of * the fix for 6473331, which adds support for Class-Path manifest * entries in JAR files. Diagnostic code is simply commented out * because rmic silently ignored these conditions historically. */ Arguably, a better long term solution would be for rmic to share this code with javac. In fact, a better long term solution would be to settle on rmic -Xnew, or, even better, rewrite rmic to use JSR269 API instead of the javadoc API.
24-05-2010

EVALUATION See Comments.
19-05-2010

SUGGESTED FIX The suggested change is to ensure that the paths are canonicalised before being added to the classpath. src/share/classes/sun/rmi/rmic/BatchEnvironment.java In private void addJarClassPath(String jarFileName, boolean warn) replace: elt = new File(jarParent, elt).toString(); with: elt = new File(jarParent, elt).getCanonicalPath();
19-05-2010