typetools / checker-framework

Pluggable type-checking for Java
http://checkerframework.org/
Other
1.02k stars 354 forks source link

Possible configuration issues in Maven #5411

Closed delanym closed 1 year ago

delanym commented 1 year ago

Hi I'm getting errors when building my Maven project with checkerframework

This error

Caused by: java.lang.NullPointerException: Cannot invoke "java.util.TreeSet.clear()" because "this.messageStore" is null
    at org.checkerframework.common.basetype.BaseTypeChecker.typeProcess (BaseTypeChecker.java:514)
    at org.checkerframework.javacutil.AbstractTypeProcessor$AttributionTaskListener.finished (AbstractTypeProcessor.java:188)

is thrown building my project.

On module A using ResourceLeakChecker, but not NullnessChecker or InterningChecker. On module B using ResourceLeakChecker and NullnessChecker. When using InterningChecker I get a different error: [ERROR] AnnotationBuilder: error: fromClass can't load Class org.checkerframework.dataflow.qual.Deterministic

Environment

Apache Maven 3.8.6 (84538c9988a25aec085021c365c560670ad80f63)
Maven home: /home/sol/.m2/wrapper/dists/apache-maven-3.8.6-bin/67568434/apache-maven-3.8.6
Java version: 17.0.5, vendor: Azul Systems, Inc., runtime: /usr/lib/jvm/zulu-17-amd64
Default locale: en_ZA, platform encoding: UTF-8
OS name: "linux", version: "5.19.0-23-generic", arch: "amd64", family: "unix"

Conf

<profile>
  <id>checkerframework</id>
  <activation>
    <property>
      <name>!nocheckerframework</name>
    </property>
  </activation>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.checkerframework</groupId>
        <artifactId>checker</artifactId>
        <version>3.27.0</version>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.checkerframework</groupId>
      <artifactId>checker</artifactId>
      <scope>provided</scope>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <annotationProcessorPaths combine.children="append">
            <path>
              <groupId>org.checkerframework</groupId>
              <artifactId>checker</artifactId>
              <version>3.27.0</version>
            </path>
          </annotationProcessorPaths>
          <annotationProcessors combine.children="append">
            <annotationProcessor>org.checkerframework.checker.resourceleak.ResourceLeakChecker</annotationProcessor>
            <!--                <annotationProcessor>org.checkerframework.checker.interning.InterningChecker</annotationProcessor>-->
            <!--                <annotationProcessor>org.checkerframework.checker.nullness.NullnessChecker</annotationProcessor>-->
          </annotationProcessors>
          <compilerArgs combine.children="append">
            <arg>-Awarns</arg>
          </compilerArgs>
        </configuration>
      </plugin>
    </plugins>
  </build>
</profile>
msridhar commented 1 year ago

What JDK version are you compiling with? Any way you could create a small repo that reproduces the problem?

delanym commented 1 year ago

@msridhar I gave the environment above. Here's a repo: https://github.com/delanym/openapi-parser.git Checkout checkerframework branch and run ./mvnw clean compile

Compilation fails with Fatal error compiling: java.lang.IllegalAccessError: class org.checkerframework.javacutil.AbstractTypeProcessor (in unnamed module @0x67eec8e1) cannot access class com.sun.tools.javac.processing.JavacProcessingEnvironment (in module jdk.compiler) because module jdk.compiler does not export com.sun.tools.javac.processing to unnamed module @0x67eec8e1

msridhar commented 1 year ago

Thanks for the details. I think you are missing the -J--add-exports arguments needed to compile on JDK 17, i.e.:

              <compilerArgs combine.children="append">
                <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED</arg>
                <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED</arg>
                <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED</arg>
                <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED</arg>
                <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED</arg>
                <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED</arg>
                <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED</arg>
                <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED</arg>
                <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED</arg>
              </compilerArgs>

That's taken from here, which gives a complete suggested Maven configuration: https://checkerframework.org/manual/#maven Does that fix the problem?

delanym commented 1 year ago

Indeed I was. This is fixed on the branch. You should get the original error now.

msridhar commented 1 year ago

@delanym I got your branch to work by (1) forking the Java compiler and (2) adding a dependence on checker-qual, which is required by the Checker Framework. Here is the patch:

diff --git a/pom.xml b/pom.xml
index e4a6c54..e680a7e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -143,6 +143,11 @@
             <artifactId>slf4j-api</artifactId>
             <version>${version.slf4j}</version>
         </dependency>
+        <dependency>
+            <groupId>org.checkerframework</groupId>
+            <artifactId>checker-qual</artifactId>
+            <version>3.27.0</version>
+        </dependency>
         <dependency>
             <groupId>ch.qos.logback</groupId>
             <artifactId>logback-classic</artifactId>
@@ -364,6 +369,7 @@
                         <artifactId>maven-compiler-plugin</artifactId>
                         <version>3.10.1</version>
                         <configuration>
+                            <fork>true</fork>
                             <annotationProcessorPaths combine.children="append">
                                 <path>
                                     <groupId>org.checkerframework</groupId>
@@ -377,6 +383,15 @@
                                 <!--                <annotationProcessor>org.checkerframework.checker.nullness.NullnessChecker</annotationProcessor>-->
                             </annotationProcessors>
                             <compilerArgs combine.children="append">
+                                <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED</arg>
+                                <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED</arg>
+                                <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED</arg>
+                                <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED</arg>
+                                <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED</arg>
+                                <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED</arg>
+                                <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED</arg>
+                                <arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED</arg>
+                                <arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED</arg>
                                 <arg>-Awarns</arg>
                             </compilerArgs>
                         </configuration>

The build still doesn't work without forking the compiler; that part is beyond my expertise.

mernst commented 1 year ago

Per https://checkerframework.org/manual/#maven, <fork>true</fork> is required, or else the JVM arguments are ignored.

delanym commented 1 year ago

I see what's happening. I had dependency on checker, thinking checker-qual would be included. It was, but my bom was downgrading the version since postgresql is published depending on it. Does postgresql really need this at runtime? I've learnt to put annotation dependencies in provided scope to avoid this - something for your docs.

You dont need to fork, just add this argument --add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED There's no need to add them to the pom @msridhar, the compiler args are in .mvn/jvm.config Changes pushed. Forking was required if you wanted to use a different javac. I remember that trying errorprone on jdk8.

msridhar commented 1 year ago

I see what's happening. I had dependency on checker, thinking checker-qual would be included.

To be clear, checker should be a dependency only on the annotation processor path, while checker-qual needs to be on the classpath. You don't want the full checker artifact in the classpath (even provided).

To confirm is this issue solved now?

delanym commented 1 year ago

Seems to be a fair deal of confusion about this dependency: https://github.com/pgjdbc/pgjdbc/pull/2262

From my side, I'm all good. Thanks for your assistance.

delanym commented 1 year ago

@msridhar as an aside I notice my builds take longer by 10% when the dependency/annotationPath are added even without specifying any checkers in <annotationProcessors>. Is something being checked by default?

msridhar commented 1 year ago

@msridhar as an aside I notice my builds take longer by 10% when the dependency/annotationPath are added even without specifying any checkers in <annotationProcessors>. Is something being checked by default?

It's quite possible the Checker Framework does a bit of work even with no checkers enabled; this scenario has not been studied carefully.

mernst commented 1 year ago

If no annotation processors are enabled, the Checker Framework shouldn't even run, because the Checker Framework is an annotation processor. Is it possible that the existence of other command-line arguments (such as --add-exports, --add-opens, -processorpath, and --module-path) is responsible for the slowdown?