From e339e183c1d60e494d266bac0c2ec05c1ec30cc6 Mon Sep 17 00:00:00 2001 From: "Archie L. Cobbs" Date: Sat, 18 Mar 2023 17:32:00 +0000 Subject: [PATCH] 7016187: `javac -h` could generate conflict .h for inner class and class name with '_' Reviewed-by: vromero --- .../com/sun/tools/javac/jvm/JNIWriter.java | 18 ++++++++++-- .../javac/nativeHeaders/NativeHeaderTest.java | 28 ++++++++++++++++++- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/JNIWriter.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/JNIWriter.java index 5ea327e2a5ee6..2de0e330796e7 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/JNIWriter.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/JNIWriter.java @@ -29,6 +29,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import javax.tools.FileObject; @@ -84,6 +85,12 @@ public class JNIWriter { */ private boolean checkAll; + /** + * Mapping from output file name to class name, for all classes we've written. + * This is used to detect when two classes generate the same output file. + */ + private final HashMap filesWritten = new HashMap<>(); + /** * If true, class files will be written in module-specific subdirectories * of the NATIVE_HEADER_OUTPUT location. @@ -183,9 +190,14 @@ public FileObject write(ClassSymbol c) throws IOException { } else { outLocn = StandardLocation.NATIVE_HEADER_OUTPUT; } - FileObject outFile - = fileManager.getFileForOutput(outLocn, - "", className.replaceAll("[.$]", "_") + ".h", null); + String fileName = className.replaceAll("[.$]", "_") + ".h"; + String prevName = filesWritten.put(fileName, className); + if (prevName != null) { + throw new IOException(String.format( + "native header file collision between %s and %s (both generate %s)", + prevName, className, fileName)); + } + FileObject outFile = fileManager.getFileForOutput(outLocn, "", fileName, null); PrintWriter out = new PrintWriter(outFile.openWriter()); try { write(out, c); diff --git a/test/langtools/tools/javac/nativeHeaders/NativeHeaderTest.java b/test/langtools/tools/javac/nativeHeaders/NativeHeaderTest.java index 1419bcc7faa7d..46084389c4529 100644 --- a/test/langtools/tools/javac/nativeHeaders/NativeHeaderTest.java +++ b/test/langtools/tools/javac/nativeHeaders/NativeHeaderTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 7150368 8003412 8000407 + * @bug 7150368 8003412 8000407 7016187 * @summary javac should include basic ability to generate native headers * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file @@ -149,6 +149,32 @@ void annoNestedClassTest(RunKind rk, GenKind gk) throws Exception { test(rk, gk, files, expect); } + @Test + void conflictTest(RunKind rk, GenKind gk) throws Exception { + + // These two classes will generate the same header file "Foo_Bar.h" + List files = new ArrayList(); + files.add(createFile("p/Foo.java", """ + public class Foo { + public static class Bar { + public static native void method1(); + } + } + """)); + files.add(createFile("p/Foo_Bar.java", """ + public class Foo_Bar { + public static native void method2(); + } + """)); + + try { + test(rk, gk, files, null); + throw new AssertionError("expected failure"); + } catch (Exception e) { + // expected + } + } + /** * The worker method for each test case. * Compile the files and verify that exactly the expected set of header files