United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6934615 Relative classpaths in jarfile manifests are handled inefficiently by rmic
JDK-6934615 : Relative classpaths in jarfile manifests are handled inefficiently by rmic

Details
Type:
Bug
Submit Date:
2010-03-12
Status:
Resolved
Updated Date:
2010-06-09
Project Name:
JDK
Resolved Date:
2010-06-09
Component:
core-libs
OS:
generic
Sub-Component:
java.rmi
CPU:
generic
Priority:
P4
Resolution:
Fixed
Affected Versions:
6u18
Fixed Versions:

Related Reports
Backport:
Relates:
Relates:
Relates:

Sub Tasks

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
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();
                                     
2010-05-19
EVALUATION

See Comments.
                                     
2010-05-19
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.
                                     
2010-05-24
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.
                                     
2010-05-24



Hardware and Software, Engineered to Work Together