From 7ba7d29c83cbc1b58f5d2d94796c93874bf6741a Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Tue, 17 Dec 2024 14:40:09 +0000 Subject: [PATCH 1/2] Add test for a JavacTool-based compiler that doesn't use standard JavaFileObjects --- .../java/javac-tool-custom-file/Compiler.java | 93 +++++++++++++++++++ .../java/javac-tool-custom-file/test.expected | 1 + .../java/javac-tool-custom-file/test.py | 5 + .../java/javac-tool-custom-file/test.ql | 5 + 4 files changed, 104 insertions(+) create mode 100644 java/ql/integration-tests/java/javac-tool-custom-file/Compiler.java create mode 100644 java/ql/integration-tests/java/javac-tool-custom-file/test.expected create mode 100644 java/ql/integration-tests/java/javac-tool-custom-file/test.py create mode 100644 java/ql/integration-tests/java/javac-tool-custom-file/test.ql diff --git a/java/ql/integration-tests/java/javac-tool-custom-file/Compiler.java b/java/ql/integration-tests/java/javac-tool-custom-file/Compiler.java new file mode 100644 index 000000000000..88f4df76e5d2 --- /dev/null +++ b/java/ql/integration-tests/java/javac-tool-custom-file/Compiler.java @@ -0,0 +1,93 @@ +import javax.lang.model.element.Modifier; +import javax.lang.model.element.NestingKind; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.ToolProvider; +import java.io.*; +import java.net.URI; +import java.util.List; +import java.util.Objects; + +public class Compiler { + public static void main(String[] args) { + + JavaCompiler.CompilationTask jc = ToolProvider.getSystemJavaCompiler().getTask( + null, null, null, null, null, + List.of( + new JavaFileObject() { + @Override + public Kind getKind() { + return Kind.SOURCE; + } + + @Override + public boolean isNameCompatible(String simpleName, Kind kind) { + return Objects.equals(simpleName, "Main"); + } + + @Override + public NestingKind getNestingKind() { + return null; + } + + @Override + public Modifier getAccessLevel() { + return null; + } + + @Override + public URI toUri() { + return URI.create("https://nonesuch.imaginary/somedir/Main.java"); + } + + @Override + public String getName() { + return "Main.java"; + } + + @Override + public InputStream openInputStream() throws IOException { + return new ByteArrayInputStream(this.getCharContent(true).toString().getBytes()); + } + + @Override + public OutputStream openOutputStream() throws IOException { + throw new IOException("No output allowed"); + } + + @Override + public Reader openReader(boolean ignoreEncodingErrors) throws IOException { + return new StringReader(this.getCharContent(ignoreEncodingErrors).toString()); + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { + return "public class Main { }"; + } + + @Override + public Writer openWriter() throws IOException { + throw new IOException("No output allowed"); + } + + @Override + public long getLastModified() { + return 0; + } + + @Override + public boolean delete() { + return false; + } + + @Override + public String toString() { + return "In-memory file with URI " + this.toUri(); + } + } + ) + ); + + jc.call(); + } +} diff --git a/java/ql/integration-tests/java/javac-tool-custom-file/test.expected b/java/ql/integration-tests/java/javac-tool-custom-file/test.expected new file mode 100644 index 000000000000..b2fc46260472 --- /dev/null +++ b/java/ql/integration-tests/java/javac-tool-custom-file/test.expected @@ -0,0 +1 @@ +| Main | diff --git a/java/ql/integration-tests/java/javac-tool-custom-file/test.py b/java/ql/integration-tests/java/javac-tool-custom-file/test.py new file mode 100644 index 000000000000..bba70043d013 --- /dev/null +++ b/java/ql/integration-tests/java/javac-tool-custom-file/test.py @@ -0,0 +1,5 @@ +import commands + +def test(codeql, java): + commands.run("javac Compiler.java") + codeql.database.create(command = "java Compiler") diff --git a/java/ql/integration-tests/java/javac-tool-custom-file/test.ql b/java/ql/integration-tests/java/javac-tool-custom-file/test.ql new file mode 100644 index 000000000000..d23ac7437597 --- /dev/null +++ b/java/ql/integration-tests/java/javac-tool-custom-file/test.ql @@ -0,0 +1,5 @@ +import java + +from Class c +where c.fromSource() +select c.getName() From 898995f6b55e2b07ca807f2bb05fa0a651b9c0f9 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 18 Dec 2024 15:29:00 +0000 Subject: [PATCH 2/2] Add change note --- .../lib/change-notes/2024-12-18-javac-tool-interception.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 java/ql/lib/change-notes/2024-12-18-javac-tool-interception.md diff --git a/java/ql/lib/change-notes/2024-12-18-javac-tool-interception.md b/java/ql/lib/change-notes/2024-12-18-javac-tool-interception.md new file mode 100644 index 000000000000..99c4756b766c --- /dev/null +++ b/java/ql/lib/change-notes/2024-12-18-javac-tool-interception.md @@ -0,0 +1,6 @@ +--- +category: minorAnalysis +--- +* `JavacTool`-based compiler interception no longer requires an `--add-opens` directive when `FileObject.toUri` is accessible. +* `JavacTool`-based compiler interception no longer throws an exception visible to the program using `JavacTool` on failure to extract a file path from a passed `JavaFileObject`. +* `JavacTool`-based compiler interception now supports files that don't simply wrap a `file://` URL, such as a source file inside a JAR, or an in-memory file, but which do implement `getCharContent`.