JDK-8156989 : Trailing empty element in classpath ignored
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang:class_loading
  • Affected Version: 9
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2016-05-14
  • Updated: 2016-10-17
  • Resolved: 2016-05-16
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 9
9 b120Fixed
Related Reports
Relates :  
Relates :  
Description
java (and javac) are defined to treat empty path elements in -classpath as ".".

It looks like there is a regression in JDK 9 such that a trailing empty path element is lost (and thus not treated as ".").

This was detected by resuscitating the javac test 
    langtools/test/tools/javac/Paths/MineField.sh
which has been disabled for a while during Jigsaw development. (Sigh).

Here is a very stripped down version that demonstrates the bug:
----------------------------------
#!/bin/sh

JDK=/opt/jdk/1.9.0

mkdir -p MyDir

echo 'public class Lib {public static void f(){}}' > Lib.java
$JDK/bin/javac -d MyDir Lib.java

echo 'public class Main {public static void main(String[] a) {Lib.f();}}' > Main.java
$JDK/bin/javac -cp MyDir Main.java

cd MyDir
$JDK/bin/java -cp ..: Main
----------------------------------

Here is the result of running the script:

$ sh -x Bug.sh
+ JDK=/opt/jdk/1.9.0
+ mkdir -p MyDir
+ echo public class Lib {public static void f(){}}
+ /opt/jdk/1.9.0/bin/javac -d MyDir Lib.java
+ echo public class Main {public static void main(String[] a) {Lib.f();}}
+ /opt/jdk/1.9.0/bin/javac -cp MyDir Main.java
+ cd MyDir
+ /opt/jdk/1.9.0/bin/java -cp ..: Main
Exception in thread "main" java.lang.NoClassDefFoundError: Lib
	at Main.main(Main.java:1)
Caused by: java.lang.ClassNotFoundException: Lib
	at jdk.internal.loader.BuiltinClassLoader.loadClass(java.base@9-ea/BuiltinClassLoader.java:366)
	at jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(java.base@9-ea/ClassLoaders.java:184)
	at java.lang.ClassLoader.loadClass(java.base@9-ea/ClassLoader.java:419)
	... 1 more

If you edit the script to run JDK 8, you get the following output (i.e. no error, as expected)

$ sh -x Bug.sh
+ JDK=/opt/jdk/1.8.0
+ mkdir -p MyDir
+ echo public class Lib {public static void f(){}}
+ /opt/jdk/1.8.0/bin/javac -d MyDir Lib.java
+ echo public class Main {public static void main(String[] a) {Lib.f();}}
+ /opt/jdk/1.8.0/bin/javac -cp MyDir Main.java
+ cd MyDir
+ /opt/jdk/1.8.0/bin/java -cp ..: Main





Comments
This test will be covered by the updated MineField.sh test in the langtools repo, added noreg-other for now.
16-05-2016

1. It appears that the last component is missed completely % $JAVA_HOME/bin/java -cp .:xx -XshowSettings:props -version 2>&1 | grep class.path java.class.path = . %JAVA_HOME/bin/java -cp xx:.. -XshowSettings:props -version 2>&1 | grep class.path java.class.path = xx 2. Not a launcher issue: % _JAVA_LAUNCHER_DEBUG=true $JAVA_HOME/bin/java -cp xx:.. -XshowSettings:props -version 2>&1 | grep class.path option[ 1] = '-Djava.class.path=xx:..' <--- launcher is setting the VM arg correctly java.class.path = xx Yes, this is a LauncherHelper issue, sorry for the noise, mea culpa.
16-05-2016

This is a corner case in the parsing of java.class.path. When are you thinking of liberating MineField.sh? This test use -Xbootclasspath/p and so can't be used with JDK 9 at this time. I don't mind writing a new test but if you have it rewritten already then let me know.
15-05-2016

As a general rule, I think empty path elements should be ignored. It is anomalous that "empty" means "." for -classpath, and I can only assume this is to preserve legacy behavior going way way back. I would not object to a formal change to the behavior of -classpath, but at this stage, it is probably less hassle to preserve the old behavior than to change it. It does seem hard to imagine that anyone is intentionally relying on this behavior (but stranger things have happened.) I think that empty path elements should be ignored for all new paths (-modulepath, -Xpatch, -upgradepath, etc) as has been the behavior for all paths other than -classpath. Currently, javac ignores empty path elements for all except -classpath.
15-05-2016

I grabbed the updated MineField.sh, uncommented the -cp "..${PS}" sub-test and it is passing now.
15-05-2016

I've attached a patch for the jdk repo to fix this. I've tested it in JPRT. I will checked the updated MineField test to check coverage and see if we need to add further tests to the jdk repo to better exercise these corner cases. At some point then we need to do the same of -Xpatch and -modulepath. Empty elements seem less likely there but we need to be consistent (and consistent between javac, java and other tools on this). Kumar - are you looking at a different issue? This looks like an issue in LauncherHelper.printPropertyValue where it special cases .path properties.
15-05-2016

Webrev (including patch) for updated MineField.sh available at http://cr.openjdk.java.net/~jjg/8149599/webrev.00/ Note these lines: In GooClass Success "$javac" ${TESTTOOLVMOPTS} -cp "..${PS}" ../Main.java # @ignore 8156989 Trailing empty element in classpath ignored #In GooClass Success "$java" ${TESTVMOPTS} -cp "..${PS}" Main The test passes as written. Remove the @ignore comment and uncomment the following line to test a patch for this bug.
14-05-2016

Have updated MineField.sh ready to go, and (almost ready to go) I have a Java rewrite, MineField.java.
14-05-2016

My guess is that somewhere in the code, there is a call of path.split(File.pathSeparator) that should be path.split(File.pathSeparator, -1) to prevent the loss of trailing empty strings
14-05-2016