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