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

The Checker Framework crashes when @Builder and @Singular are used together #4254

Closed
RamAnvesh opened this issue Feb 9, 2021 · 19 comments
Closed
Assignees

Comments

@RamAnvesh
Copy link

RamAnvesh commented Feb 9, 2021

  • commands
    Running checker framework nullness checker from maven

Checker Framework versions:
checker-3.10.0.jar
checker-util-3.10.0.jar
checker-qual-3.10.0.jar

javac Version:
javac-9-dev-r4023-3.jar

  • inputs
import lombok.Builder;
import lombok.Singular;

import java.util.List;

@Builder
public class LombokTest {
    @Singular List<String> strings;
}
  • outputs
[ERROR] error: SourceChecker.typeProcess: unexpected Throwable (ClassCastException) while processing LombokTest.java; message: java.lang.Integer cannot be cast to java.lang.Void
[ERROR]   ; The Checker Framework crashed.  Please report the crash.
  Compilation unit: LombokTest.java
  Last visited tree at line 8 column 1:
  @Builder
  Exception: java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Void; java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Void
  	at org.checkerframework.dataflow.cfg.node.NullLiteralNode.getValue(NullLiteralNode.java:30)
  	at org.checkerframework.dataflow.cfg.node.NullLiteralNode.getValue(NullLiteralNode.java:16)
  	at org.checkerframework.dataflow.cfg.node.ValueLiteralNode.equals(ValueLiteralNode.java:58)
  	at org.checkerframework.dataflow.cfg.node.NullLiteralNode.equals(NullLiteralNode.java:45)
  	at java.util.ArrayList.indexOf(ArrayList.java:321)
  	at java.util.ArrayList.contains(ArrayList.java:304)
  	at org.checkerframework.dataflow.analysis.AbstractAnalysis.getValue(AbstractAnalysis.java:199)
  	at org.checkerframework.dataflow.analysis.AbstractAnalysis.getValue(AbstractAnalysis.java:282)
  	at org.checkerframework.framework.type.GenericAnnotatedTypeFactory.getInferredValueFor(GenericAnnotatedTypeFactory.java:1745)
  	at org.checkerframework.framework.type.GenericAnnotatedTypeFactory.addComputedTypeAnnotations(GenericAnnotatedTypeFactory.java:1696)
  	at org.checkerframework.framework.type.GenericAnnotatedTypeFactory.addComputedTypeAnnotations(GenericAnnotatedTypeFactory.java:1643)
  	at org.checkerframework.framework.type.AnnotatedTypeFactory.getAnnotatedType(AnnotatedTypeFactory.java:1058)
  	at org.checkerframework.framework.type.AnnotatedTypeFactory.binaryTreeArgTypes(AnnotatedTypeFactory.java:2604)
  	at org.checkerframework.framework.type.treeannotator.PropagationTreeAnnotator.visitBinary(PropagationTreeAnnotator.java:142)
  	at org.checkerframework.framework.type.treeannotator.PropagationTreeAnnotator.visitBinary(PropagationTreeAnnotator.java:33)
  	at com.sun.tools.javac.tree.JCTree$JCBinary.accept(JCTree.java:1993)
  	at com.sun.source.util.SimpleTreeVisitor.visit(SimpleTreeVisitor.java:80)
  	at org.checkerframework.framework.type.treeannotator.ListTreeAnnotator.defaultAction(ListTreeAnnotator.java:52)
  	at org.checkerframework.framework.type.treeannotator.ListTreeAnnotator.defaultAction(ListTreeAnnotator.java:20)
  	at com.sun.source.util.SimpleTreeVisitor.visitBinary(SimpleTreeVisitor.java:515)
  	at org.checkerframework.framework.type.treeannotator.TreeAnnotator.visitBinary(TreeAnnotator.java:55)
  	at org.checkerframework.framework.type.treeannotator.TreeAnnotator.visitBinary(TreeAnnotator.java:21)
  	at com.sun.tools.javac.tree.JCTree$JCBinary.accept(JCTree.java:1993)
  	at com.sun.source.util.SimpleTreeVisitor.visit(SimpleTreeVisitor.java:80)
  	at org.checkerframework.framework.type.GenericAnnotatedTypeFactory.addComputedTypeAnnotations(GenericAnnotatedTypeFactory.java:1683)
  	at org.checkerframework.framework.type.GenericAnnotatedTypeFactory.addComputedTypeAnnotations(GenericAnnotatedTypeFactory.java:1643)
  	at org.checkerframework.framework.type.AnnotatedTypeFactory.getAnnotatedType(AnnotatedTypeFactory.java:1058)
  	at org.checkerframework.framework.flow.CFAbstractTransfer.getValueFromFactory(CFAbstractTransfer.java:237)
  	at org.checkerframework.framework.flow.CFAbstractTransfer.visitNode(CFAbstractTransfer.java:634)
  	at org.checkerframework.framework.flow.CFAbstractTransfer.visitNode(CFAbstractTransfer.java:97)
  	at org.checkerframework.dataflow.cfg.node.AbstractNodeVisitor.visitEqualTo(AbstractNodeVisitor.java:190)
  	at org.checkerframework.framework.flow.CFAbstractTransfer.visitEqualTo(CFAbstractTransfer.java:787)
  	at org.checkerframework.framework.flow.CFAbstractTransfer.visitEqualTo(CFAbstractTransfer.java:97)
  	at org.checkerframework.dataflow.cfg.node.EqualToNode.accept(EqualToNode.java:31)
  	at org.checkerframework.dataflow.analysis.AbstractAnalysis.callTransferFunction(AbstractAnalysis.java:340)
  	at org.checkerframework.dataflow.analysis.ForwardAnalysisImpl.callTransferFunction(ForwardAnalysisImpl.java:390)
  	at org.checkerframework.dataflow.analysis.ForwardAnalysisImpl.performAnalysisBlock(ForwardAnalysisImpl.java:130)
  	at org.checkerframework.dataflow.analysis.ForwardAnalysisImpl.performAnalysis(ForwardAnalysisImpl.java:107)
  	at org.checkerframework.framework.flow.CFAbstractAnalysis.performAnalysis(CFAbstractAnalysis.java:109)
  	at org.checkerframework.framework.type.GenericAnnotatedTypeFactory.analyze(GenericAnnotatedTypeFactory.java:1385)
  	at org.checkerframework.framework.type.GenericAnnotatedTypeFactory.performFlowAnalysis(GenericAnnotatedTypeFactory.java:1293)
  	at org.checkerframework.framework.type.GenericAnnotatedTypeFactory.checkAndPerformFlowAnalysis(GenericAnnotatedTypeFactory.java:1730)
  	at org.checkerframework.framework.type.GenericAnnotatedTypeFactory.preProcessClassTree(GenericAnnotatedTypeFactory.java:360)
  	at org.checkerframework.common.basetype.BaseTypeVisitor.visitClass(BaseTypeVisitor.java:328)
  	at org.checkerframework.common.basetype.BaseTypeVisitor.visitClass(BaseTypeVisitor.java:176)
  	at com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:808)
  	at com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:56)
  	at org.checkerframework.framework.source.SourceVisitor.visit(SourceVisitor.java:82)
  	at org.checkerframework.framework.source.SourceChecker.typeProcess(SourceChecker.java:976)
  	at org.checkerframework.common.basetype.BaseTypeChecker.typeProcess(BaseTypeChecker.java:507)
  	at org.checkerframework.common.basetype.BaseTypeChecker.typeProcess(BaseTypeChecker.java:500)
  	at org.checkerframework.javacutil.AbstractTypeProcessor$AttributionTaskListener.finished(AbstractTypeProcessor.java:190)
  	at com.sun.tools.javac.api.ClientCodeWrapper$WrappedTaskListener.finished(ClientCodeWrapper.java:817)
  	at com.sun.tools.javac.api.MultiTaskListener.finished(MultiTaskListener.java:120)
  	at com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1425)
  	at com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1384)
  	at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:980)
  	at com.sun.tools.javac.main.Main.compile(Main.java:302)
  	at com.sun.tools.javac.main.Main.compile(Main.java:162)
  	at com.sun.tools.javac.Main.compile(Main.java:55)
  	at com.sun.tools.javac.Main.main(Main.java:41)
error: SourceChecker.typeProcess: unexpected Throwable (ClassCastException) while processing LombokTest.java; message: java.lang.Integer cannot be cast to java.lang.Void
  ; The Checker Framework crashed.  Please report the crash.
  Compilation unit: LombokTest.java
  Last visited tree at line 8 column 1:
  @Builder
  Exception: java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Void; java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Void
  	at org.checkerframework.dataflow.cfg.node.NullLiteralNode.getValue(NullLiteralNode.java:30)
  	at org.checkerframework.dataflow.cfg.node.NullLiteralNode.getValue(NullLiteralNode.java:16)
  	at org.checkerframework.dataflow.cfg.node.ValueLiteralNode.equals(ValueLiteralNode.java:58)
  	at org.checkerframework.dataflow.cfg.node.NullLiteralNode.equals(NullLiteralNode.java:45)
  	at java.util.ArrayList.indexOf(ArrayList.java:321)
  	at java.util.ArrayList.contains(ArrayList.java:304)
  	at org.checkerframework.dataflow.analysis.AbstractAnalysis.getValue(AbstractAnalysis.java:199)
  	at org.checkerframework.dataflow.analysis.TransferInput.getValueOfSubNode(TransferInput.java:178)
  	at org.checkerframework.framework.flow.CFAbstractTransfer.visitEqualTo(CFAbstractTransfer.java:792)
  	at org.checkerframework.framework.flow.CFAbstractTransfer.visitEqualTo(CFAbstractTransfer.java:97)
  	at org.checkerframework.dataflow.cfg.node.EqualToNode.accept(EqualToNode.java:31)
  	at org.checkerframework.dataflow.analysis.AbstractAnalysis.callTransferFunction(AbstractAnalysis.java:340)
  	at org.checkerframework.dataflow.analysis.ForwardAnalysisImpl.callTransferFunction(ForwardAnalysisImpl.java:390)
  	at org.checkerframework.dataflow.analysis.ForwardAnalysisImpl.performAnalysisBlock(ForwardAnalysisImpl.java:130)
  	at org.checkerframework.dataflow.analysis.ForwardAnalysisImpl.performAnalysis(ForwardAnalysisImpl.java:107)
  	at org.checkerframework.framework.flow.CFAbstractAnalysis.performAnalysis(CFAbstractAnalysis.java:109)
  	at org.checkerframework.framework.type.GenericAnnotatedTypeFactory.analyze(GenericAnnotatedTypeFactory.java:1385)
  	at org.checkerframework.framework.type.GenericAnnotatedTypeFactory.performFlowAnalysis(GenericAnnotatedTypeFactory.java:1293)
  	at org.checkerframework.framework.type.GenericAnnotatedTypeFactory.checkAndPerformFlowAnalysis(GenericAnnotatedTypeFactory.java:1730)
  	at org.checkerframework.framework.type.GenericAnnotatedTypeFactory.preProcessClassTree(GenericAnnotatedTypeFactory.java:360)
  	at org.checkerframework.common.basetype.BaseTypeVisitor.visitClass(BaseTypeVisitor.java:328)
  	at org.checkerframework.common.basetype.BaseTypeVisitor.visitClass(BaseTypeVisitor.java:176)
  	at com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:808)
  	at com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:56)
  	at org.checkerframework.framework.source.SourceVisitor.visit(SourceVisitor.java:82)
  	at org.checkerframework.framework.source.SourceChecker.typeProcess(SourceChecker.java:976)
  	at org.checkerframework.common.basetype.BaseTypeChecker.typeProcess(BaseTypeChecker.java:507)
  	at org.checkerframework.javacutil.AbstractTypeProcessor$AttributionTaskListener.finished(AbstractTypeProcessor.java:190)
  	at com.sun.tools.javac.api.ClientCodeWrapper$WrappedTaskListener.finished(ClientCodeWrapper.java:817)
  	at com.sun.tools.javac.api.MultiTaskListener.finished(MultiTaskListener.java:120)
  	at com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1425)
  	at com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1384)
  	at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:980)
  	at com.sun.tools.javac.main.Main.compile(Main.java:302)
  	at com.sun.tools.javac.main.Main.compile(Main.java:162)
  	at com.sun.tools.javac.Main.compile(Main.java:55)
  	at com.sun.tools.javac.Main.main(Main.java:41)
  • expectation.
    No Crash
@mernst
Copy link
Member

mernst commented Feb 10, 2021

Thanks for getting in touch. I'm sorry you are having trouble.
Unfortunately, I cannot reproduce the problem, because you did not provide a command that can be pasted into a command shell.

Using the version of the Checker Framework at HEAD, I ran:

javacheck -processor nullness -cp /home/mernst/.gradle/caches/modules-2/files-2.1/org.projectlombok/lombok/1.18.18/481f5bfed3ae29f656eedfe9e98c8365b8ba5c57/lombok-1.18.18.jar LombokTest.java

and the output was:

LombokTest.java:7: error: [initialization.field.uninitialized] the default constructor does not initialize field strings
@Singular List strings;
               ^
1 error

If you can provide a way to reproduce your problem, we will take a look. Thanks!

@RamAnvesh
Copy link
Author

RamAnvesh commented Feb 10, 2021

I upgraded to lombok-1.18.18 and this fixed the issue.

Sorry I tried to reproduce the issue on commandline and I am not able to do this either for 1.18.16 or 1.18.18
But in Maven, the framework is reliably crashing when using 1.18.16 but not when using 1.18.18.

I am unblocked. Please feel free to close this issue/investigate further as you see fit.
Please let me know if I can help in some way - given the commandline is behaving differently from maven based use.

Thanks.

@mernst
Copy link
Member

mernst commented Feb 10, 2021

Thanks for investigating. I'm glad that upgrading worked around the problem.

I got the same result (no crash) with lombok-1.18.16.jar on the classpath. (This test was again using the Checker Framework from HEAD.)

You could make the problem reproducible for us by providing a complete Maven project (including the pom.xml file and the source code files); then the command to reproduce would be a mvn command.

Or, you could close this issue.

@RamAnvesh
Copy link
Author

RamAnvesh commented Feb 11, 2021

Created repo: https://github.com/RamAnvesh/checker-framework-4254

Command:
mvn clean install

@RamAnvesh
Copy link
Author

@mernst Is this maven project (https://github.com/RamAnvesh/checker-framework-4254) sufficient to reproduce the issue?

I think the issue with the command line is that though Lombok is on the classpath, it is not acting as an annotation processor and hence is not generating any bytecode. That's why the error we are getting is that which we would have got if there were no Lombok annotations in the class (no constructor), where as the issue seems to be in the generated byte code. The above maven project invokes lombok annotation processor and hence is reproducing the issue.

@mernst
Copy link
Member

mernst commented Feb 18, 2021

I can reproduce the problem by running

git clone https://github.com/RamAnvesh/checker-framework-4254
cd checker-framework-4254
mvn clean install

Thanks for the details.

@mernst mernst self-assigned this Feb 25, 2021
@mernst
Copy link
Member

mernst commented Mar 1, 2021

When running the Checker Framework and Lombok together, you need to run delombok.
This is explained in the section Type-checking code with Lombok annotations in the Checker Framework Manual.
I don't see that in your Maven build file, however. Could you please correct the build file?

@an-cwi
Copy link

an-cwi commented Mar 4, 2021

I'm using the CF Gradle plugin and it's been working fine with various Lombok annotations for a long time. Just today I tried using @Builder and @Singular together, and have the same issue, so it seems to be something specific to that combination.

I tried to create a minimal reproduction of the issue, but unfortunately was unsuccessful (the Gradle build succeeds).

Versions:
CF Gradle plugin: 0.5.17
CF: 3.11.0

@mernst
Copy link
Member

mernst commented Mar 4, 2021

@an-cwi Thanks for chiming in. We are all frustrated by the inability to reproduce the issue.

If I understand correctly, you have a reproduction of the issue, but it's not minimal. Can you share the non-minimal example? If not, would it be possible for you to turn on some debugging options and share the logs with us?

https://github.com/an-cwi/checker-framework-4254/blob/main/build.gradle suggests that you are using lombok-1.18.16. @RamAnvesh upgraded from lombok-1.18.16 to lombok-1.18.18 and that fixed the problem for him. Could you please try that?

@an-cwi
Copy link

an-cwi commented Mar 4, 2021

Tried updating lombok (pushed to repo), but no change.

I wouldn't be able to share the full reproduction unfortunately (private corporate repo), and there are a lot of config differences between it and minimal repo, so it would take a while to isolate systematically. For starters, I can certainly enable some extra debugging options and share logs, though. Suggestions?

@mernst
Copy link
Member

mernst commented Mar 5, 2021

Thanks!

  1. Can you share the stack trace? Is it the same as the stack trace in the original bug report? That one shows that in NullLiteralNode.getValue, the LiteralTree for the NullLiteralNode contains an Integer, which should not be possible.
public class NullLiteralNode extends ValueLiteralNode {

    /**
     * Create a new NullLiteralNode.
     *
     * @param t the tree for the literal value
     */
    public NullLiteralNode(LiteralTree t) {
        super(t);
        assert t.getKind() == Tree.Kind.NULL_LITERAL;
    }

    @Override
    public Void getValue() {
        return (Void) tree.getValue();
    }
  1. Can you run with assertions enabled? I am wondering whether:
  • the NullLiteralNode constructor is called with an Integer LiteralTree but the assertion is disabled, or
  • Lombok changes the AST later.
  1. Can you run using a special version of the Checker Framework (I would supply jar files with extra diagnostics), or is that inconvenient and you only want to use the Checker Framework from Maven Central?

@an-cwi
Copy link

an-cwi commented Mar 5, 2021

  1. The stack trace appears to be identical with respect to CF, only differing when you get down to where Gradle invokes javac
    stack-trace.txt

  2. I haven't found an option to run CF with assertions enabled. It appears the -ea flag is only available when running java, vs. when compiling it, and I'm not familiar with how CF itself is invoked during compilation. Could you please guide me?

  3. I think I could run locally with a custom JAR

@mernst
Copy link
Member

mernst commented Mar 5, 2021

Thanks for the stack trace. It's good to know that the symptoms are the same.

javac is a Java program that runs on a JVM, and you can pass command-line arguments to that JVM using the -J command-line argument. For example, you can pass -J-ea to javac to enable assertions. (Note there is only one, not two, hyphens before the "ea".)

But, I'll send you a jar instead. Do you want it here or (to reduce clutter here) as a gist or directly by email?

@an-cwi
Copy link

an-cwi commented Mar 5, 2021

Thanks for the explanation of passing args to the JVM. I see that noted in the CF manual now (though not about assertions specifically). It turns out that in Gradle -ea can be added directly through CompileOptions.forkOptions.jvmArgs. While it doesn't look like the CF Gradle plugin itself has support for forkOptions.jvmArgs, I configured the compileJava task directly to add the -ea flag.

Error output is the same, no assertions failing.

Let's follow up offline to continue debugging.

@mernst
Copy link
Member

mernst commented Mar 10, 2021

This is indeed a bug in Lombok: projectlombok/lombok#2695 .
It was fixed in release lombok-1.18.18.

Two mysteries remain:

  • Why did upgrading to lombok-1.18.18 not fix the problem for you? Is it possible that some part of your build is still using lombok-1.18.16?
  • You are using the Gradle plugin, which ought to never run Lombok and the Checker Framework at the same time. That is, the plugin ought to run Lombok, then run delombok, then run the Checker Framework on the delomboked source code. So, the original bug should never have been visible to you, though it would be visible to people (like the original reporter) who are using Maven. Is it possible that some part of your build process is not using the Gradle plugin? (Alternatively, is it possible that the Gradle plugin sometimes lets Lombok and the Checker Framework run at the same time? @kelloggm could chime in on this or ask you for information to confirm or deny the culpability of the Gradle plugin and your use of it.)

@an-cwi
Copy link

an-cwi commented Mar 10, 2021

Turns out updating to lombok:1.18.18 did fix the issue in my full project; really sorry for not trying that sooner. Not sure about the minimal reproduction though...

@mernst
Copy link
Member

mernst commented Mar 10, 2021

I'm glad this is working for you now, and you have confirmed that the fix for the original poster worked for you too.
I had interpreted your comment "Tried updating lombok (pushed to repo), but no change." as saying that you had tried Lombok 1.18.18 as the original poster had.

I'm still curious why Lombok and the Checker Framework ran at the same time; this seems like a possible problem with the Gradle plugin.

@an-cwi
Copy link

an-cwi commented Mar 10, 2021

Yeah, if I remember correctly, I only tried updating lombok in the minimal reproduction at that point. Clearly I should have also tried it in the main project at the same time. Apologies again for the wild goose chase.

@mernst
Copy link
Member

mernst commented Mar 10, 2021

The main thing is that the problem is resolved for you. That is great. Please let us know if you have other problems. I'm going to close this issue now.

@mernst mernst closed this as completed Mar 10, 2021
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

3 participants