RFR: 8263926: JavacFileManager.hasExplicitLocation fails with NPE while compiling
Guoxiong Li
gli at openjdk.java.net
Thu Jun 17 15:50:53 UTC 2021
Hi all,
The compiler fails with NullPointerException while building the maven project provided by the user in [JDK-8263926](https://bugs.openjdk.java.net/browse/JDK-8263926).
Actually, the patch is simple. We only need to add a `null` check before using the `msym.sourceLocation`.
- if (fileManager.contains(msym.sourceLocation, fo))
+ if (msym.sourceLocation != null && fileManager.contains(msym.sourceLocation, fo))
But we can't verify whether the problem is solved because the code provided by the user is complex so that we have no way to wtite a regression test.
Recently, I deeply researched the relationship of the source code provided by the user
and construct a minimal test case to verify the patch.
The minimal test was attached to the JBS just now.
The attached test reproduces the bug by using the shell script instead of maven.
And the test case `SourceLocationNotExist.java` at this patch is another way to reproduce the bug.
The steps in `SourceLocationNotExist.java` is the same as the shell script mentioned above.
Given that the bug is hard to be reproduced, I give some comments here.
1. We need to construct a jar file which has both `*.java` files and `*.class` files and has no named module.
First, I compile the file `test/TestUnnamedModule.java` into `test/TestUnnamedModule.class`.
Then I use the `jar` tool to construct the jar file `test.jar`, which contains both `test/TestUnnamedModule.java` and `test/TestUnnamedModule.class`.
Commands are like:
`javac test/TestUnnamedModule.java` and
`jar -c -f test.jar test/TestUnnamedModule.class test/TestUnnamedModule.java`
2. The last modified time of the `*.java` files should be newer than that of the `*.class` files.
Because the compiler implicitly choose the last modified file if both source files and class files are present.
We need the compiler the choose the `*.java` files to reproduce the bug.
So before using the `jar` command, we need to update the modified time of the `*.java` files to let it newer than `*.class` files.
Command is like: `touch test/TestUnnamedModule.java`.
3. We need to use the class of the `test.jar` in a named module.
I construct a module named `use`, which has a module file `module-info.java` and a source file `TestUse.java`.
You can see the `TestUse.java` has a statement `import test.TestUnnamedModule;` to use the `test.jar`.
4. The `module-info.java` of the module `use` can't have the directive `requires test`. Because the name `test` is the automatic module name of the jar file `test.jar`.
5. When compiling the module `use` mentioned above, we must use the option `-sourcepath` and the `test.jar` is not the argument of the `-sourcepath` and `--module-path`.
Command is like: `javac -classpath test.jar -d use -sourcepath use use/module-info.java use/TestUse.java`
We can see that these five requirements are difficult to meet.
- Generally, our jar files shouldn't have the `*.java` files and only have the `*.class` files. But some libs that the user uses have these `*.java`files unexpectedly .
- And the class files are always compiled from the source files so that it is almost impossible that the last modified time of the `*.java` files is newer than `*.class` files.
- Generally, if we use the module system to construct our source code, we should compile the source code by using option `--module-path` instead of `-classpath`.
Command is like: javac **--module-path** test.jar -d use -sourcepath use use/module-info.java use/TestUse.java
instead of: javac **-classpath** test.jar -d use -sourcepath use use/module-info.java use/TestUse.java
However, the option `-classpath` is used by the maven at this situation (which no `requires` directive is in the `module-info.java`).
It is a combination of the java compiler(has no null check), the maven building tools(use `-classpath`),
the extra libraries(have `*.java` files in the jar file) and the user's moduled project codes(have no corresponding module directive).
Anyway, we actually meet it now which is provided by the user.
Hope you are not confused by these descriptions.
Thanks for taking the time to review.
Best Regards,
-- Guoxiong
-------------
Commit messages:
- 8263926: JavacFileManager.hasExplicitLocation fails with NPE while compiling
Changes: https://git.openjdk.java.net/jdk/pull/4523/files
Webrev: https://webrevs.openjdk.java.net/?repo=jdk&pr=4523&range=00
Issue: https://bugs.openjdk.java.net/browse/JDK-8263926
Stats: 167 lines in 2 files changed: 166 ins; 0 del; 1 mod
Patch: https://git.openjdk.java.net/jdk/pull/4523.diff
Fetch: git fetch https://git.openjdk.java.net/jdk pull/4523/head:pull/4523
PR: https://git.openjdk.java.net/jdk/pull/4523
More information about the compiler-dev
mailing list