Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Java: InaccessibleObjectException raised on using JavacTool with a JarFileObject #17204

Open
smowton opened this issue Aug 12, 2024 · 1 comment

Comments

@smowton
Copy link
Contributor

smowton commented Aug 12, 2024

From a comment posted to #7535 by @dwnusbaum:

We are using the java.compiler module and JavaCompiler as part of our (Maven) build process. Here is the full stack trace in our case. com.cloudbees.groovy.cps.tool.Driver is our build code, and everything works fine on Java 17 when not using the CodeQL autobuild.

  [2024-06-20 14:11:44] [autobuild] Exception in thread "main" java.lang.RuntimeException: Unknown file object: JarFileObject[/home/runner/work/workflow-cps-plugin/workflow-cps-plugin/lib/target/groovy-cps-dgm-builder-999999-SNAPSHOT-jar-with-dependencies.jar:/org/codehaus/groovy/runtime/StringGroovyMethods.java]
  [2024-06-20 14:11:44] [autobuild] 	at com.semmle.extractor.java.interceptors.JavacToolInterceptor.getTask(JavacToolInterceptor.java:216)
  [2024-06-20 14:11:44] [autobuild] 	at jdk.compiler/com.sun.tools.javac.api.JavacTool.SEMMLE_INTERCEPT$1(JavacTool.java)
  [2024-06-20 14:11:44] [autobuild] 	at jdk.compiler/com.sun.tools.javac.api.JavacTool.getTask(JavacTool.java:200)
  [2024-06-20 14:11:44] [autobuild] 	at jdk.compiler/com.sun.tools.javac.api.JavacTool.getTask(JavacTool.java:119)
  [2024-06-20 14:11:44] [autobuild] 	at jdk.compiler/com.sun.tools.javac.api.JavacTool.getTask(JavacTool.java:68)
  [2024-06-20 14:11:44] [autobuild] 	at com.cloudbees.groovy.cps.tool.Driver.run(Driver.java:59)
  [2024-06-20 14:11:44] [autobuild] 	at com.cloudbees.groovy.cps.tool.Driver.main(Driver.java:23)
  [2024-06-20 14:11:44] [autobuild] Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make public java.net.URI com.sun.tools.javac.file.PathFileObject$JarFileObject.toUri() accessible: module jdk.compiler does not "opens com.sun.tools.javac.file" to unnamed module @22d8cfe0
  [2024-06-20 14:11:44] [autobuild] 	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
  [2024-06-20 14:11:44] [autobuild] 	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
  [2024-06-20 14:11:44] [autobuild] 	at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)
  [2024-06-20 14:11:44] [autobuild] 	at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)
  [2024-06-20 14:11:44] [autobuild] 	at com.semmle.extractor.java.interceptors.JavacToolInterceptor.getTask(JavacToolInterceptor.java:196)
  [2024-06-20 14:11:44] [autobuild] 	... 6 more

We can work around the issue by adding --add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED to our build script as in jenkinsci/workflow-cps-plugin#917, but we would prefer not to have to do this.

For what it's worth, it seems unusual that com.semmle.extractor.java.interceptors.JavacToolInterceptor is trying to change the accessibility of PathFileObject$JarFileObject.toUri(). The class in question implements javax.tools.JavaFileObject, which implements javax.tools.FileObject, which has a public toUri() method, and those interfaces are part of the public API of the java.compiler module.

@smowton
Copy link
Contributor Author

smowton commented Aug 12, 2024

The unusual factor here is the usage of JarFileObject with JavacTool. Our Java extractor needs to convert the FileObjects passed to JavacTool.getTask into filesystem paths, and currently only supports SimpleFileObject (i.e., a "real" file on disk).

There are three shortcomings of our extractor to address here:

  1. The handling of JarFileObject is non-uniform between the scenarios when SomeFileObject.toUri is usable (where SomeFileObject is the real type of the passed FileObject instance), and the scenario where it isn't and we try to fall back on parsing FileObject.toString. In both cases we only currently support SimpleFileObject and classes that behave substantially like it, but we warn and continue when the toUri route finds an unexpected result (e.g. a JarFileObject), whereas we raise the hard exception posted above when using the toString route. This should be made uniform. This is why the OP's fix of passing --add-opens seems to work -- it moves us from the less-tolerant toString code to the more-tolerant toUri code.
  2. As the OP notes, it is possible to use the toUri route more often -- since the toString case is normally quite reliable, we hadn't addressed this, but it is easy to walk the class hierarchy and use FileObject.toUri, and this helps us address point (3) as well:
  3. We currently don't handle non-SimpleFileObject files, e.g. JarFileObject, at all. I have a draft PR to export these to a temporary directory and try referring to them from there-- if this seems to work for at least some cases it can't be worse than our current code which always fails in such circumstances (except perhaps the outside chance of writing a lot of text to a temporary directory and wasting disk space).

Note that even with this fix, the files referenced by the linked Jenkins code would not end up in the CodeQL database. This is because their translator uses JavacTool for its parse-and-analyse phase only; it doesn't actually call JavacTask.call, which is our cue to call the CodeQL java extractor. This is probably expected, since we are trying to trace Java build steps, and the source files referenced as JarFileObjects (e.g. org/codehaus/groovy/runtime/StringGroovyMethods.java) are not in fact compiled by JavacTool.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant