RFR: 8296656: java.lang.NoClassDefFoundError exception on running fully legitimate code
Archie L. Cobbs
duke at openjdk.org
Mon Mar 20 14:04:53 UTC 2023
This bug and a few others fall into the "output file clash" bucket. This is when the compiler thinks it's writing out two separate files, but due to the way the O/S filesystem maps `Path`'s to actual files, it's really writing the same file twice.
This is usually due to case-insensitive filesystems, but can also be due to how a filesystem "normalizes" file names. For example, on MacOS, compiling this class will generate such a clash:
public class Test {
interface Cafe\u0301 {
}
interface Caf\u00e9 {
}
}
The reason is that `\u0301` is the Unicode character "Combining Acute Accent" which means "stick an accent over the previous character". So MacOS normalizes a `e` followed by a `\u0301` into a Unicode `\u00e9`, that is, `é`. However, the Java language treats these the two names `Cafe\u0301` and `Caf\u00e9` as distinct.
It's infeasible to truly "fix" this problem, so we resort here to a salve, which is to add a new compiler flag `--detect-output-file-clashes` that enables detection of output file clashes. When the flag is enabled, and a clash is detected, an error is immediately thrown. For example, compiling the example above gives this:
$ javac --help-extra
...
--detect-output-file-clashes
Generate an error if any output file is overwritten during compilation. This can occur, for example,
on case-insensitive filesystems. This applies to class files, native header files, and source files.
...
$ javac --detect-output-file-clashes Test.java
Test.java:4: error: error while writing Café: output file clash: /Users/archie/test/Test$Café.class
interface Caf\u00e9 {
^
1 error
This at least gives people at risk of encountering this problem a way to turn a runtime error into a compile-time error.
**Outstanding Questions**
* Is making this optional via an (extended) flag `--detect-output-file-clashes` the best way to address this?
* Does the new field `BaseFileManager.outputFilesWritten` ever need to be cleared? Can the file manager be used for multiple compilations? If so, is there some "reset" step we should hook into?
-------------
Commit messages:
- Add new javac flag "--detect-output-file-clashes".
Changes: https://git.openjdk.org/jdk/pull/12754/files
Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=12754&range=00
Issue: https://bugs.openjdk.org/browse/JDK-8296656
Stats: 230 lines in 6 files changed: 228 ins; 0 del; 2 mod
Patch: https://git.openjdk.org/jdk/pull/12754.diff
Fetch: git fetch https://git.openjdk.org/jdk pull/12754/head:pull/12754
PR: https://git.openjdk.org/jdk/pull/12754
More information about the compiler-dev
mailing list