RFR: 8263926: JavacFileManager.hasExplicitLocation fails with NPE while compiling [v3]

Guoxiong Li gli at openjdk.java.net
Fri Jun 18 16:13:04 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

Guoxiong Li has updated the pull request incrementally with one additional commit since the last revision:

  Revise the method ClassFinder#scanUserPaths. Address the situation when the haveSourcePath is true and the includeSourcePath is false

-------------

Changes:
  - all: https://git.openjdk.java.net/jdk/pull/4523/files
  - new: https://git.openjdk.java.net/jdk/pull/4523/files/d98b4e46..fd4be911

Webrevs:
 - full: https://webrevs.openjdk.java.net/?repo=jdk&pr=4523&range=02
 - incr: https://webrevs.openjdk.java.net/?repo=jdk&pr=4523&range=01-02

  Stats: 33 lines in 2 files changed: 23 ins; 0 del; 10 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