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

Crash When Casting Raw Type to Parameterized Type #1019

Closed
ahauschulte opened this issue Aug 17, 2024 · 2 comments · Fixed by #1021
Closed

Crash When Casting Raw Type to Parameterized Type #1019

ahauschulte opened this issue Aug 17, 2024 · 2 comments · Fixed by #1021

Comments

@ahauschulte
Copy link

ahauschulte commented Aug 17, 2024

Summary

When analyzing code with NullAway that involves casting a raw type to a parameterized type, a compilation failure occurs, leading to the following stack trace.

An unhandled exception was thrown by the Error Prone static analysis plugin.
[ERROR]      Please report this at https://github.com/google/error-prone/issues/new and include the following:
[ERROR]   
[ERROR]      error-prone version: 2.30.0
[ERROR]      BugPattern: NullAway
[ERROR]      Stack Trace:
[ERROR]      java.lang.RuntimeException: Number of types arguments in java.util.List does not match java.util.List<java.lang.String>
[ERROR]   	at com.uber.nullaway.generics.CheckIdenticalNullabilityVisitor.visitClassType(CheckIdenticalNullabilityVisitor.java:40)
[ERROR]   	at com.uber.nullaway.generics.CheckIdenticalNullabilityVisitor.visitClassType(CheckIdenticalNullabilityVisitor.java:14)
[ERROR]   	at jdk.compiler/com.sun.tools.javac.code.Type$ClassType.accept(Type.java:1050)
[ERROR]   	at com.uber.nullaway.generics.GenericsChecks.identicalTypeParameterNullability(GenericsChecks.java:413)
[ERROR]   	at com.uber.nullaway.generics.GenericsChecks.subtypeParameterNullability(GenericsChecks.java:442)
[ERROR]   	at com.uber.nullaway.generics.GenericsChecks.checkTypeParameterNullnessForFunctionReturnType(GenericsChecks.java:392)
[ERROR]   	at com.uber.nullaway.NullAway.checkReturnExpression(NullAway.java:918)
[ERROR]   	at com.uber.nullaway.NullAway.matchReturn(NullAway.java:379)
[ERROR]   	at com.google.errorprone.scanner.ErrorProneScanner.processMatchers(ErrorProneScanner.java:449)
[ERROR]   	at com.google.errorprone.scanner.ErrorProneScanner.visitReturn(ErrorProneScanner.java:816)
[ERROR]   	at com.google.errorprone.scanner.ErrorProneScanner.visitReturn(ErrorProneScanner.java:150)
[ERROR]   	at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCReturn.accept(JCTree.java:1736)
[ERROR]   	at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:92)
[ERROR]   	at com.google.errorprone.scanner.Scanner.scan(Scanner.java:74)
[ERROR]   	at com.google.errorprone.scanner.Scanner.scan(Scanner.java:48)
[ERROR]   	at jdk.compiler/com.sun.source.util.TreeScanner.scan(TreeScanner.java:111)
[ERROR]   	at jdk.compiler/com.sun.source.util.TreeScanner.visitBlock(TreeScanner.java:272)
[ERROR]   	at com.google.errorprone.scanner.ErrorProneScanner.visitBlock(ErrorProneScanner.java:520)
[ERROR]   	at com.google.errorprone.scanner.ErrorProneScanner.visitBlock(ErrorProneScanner.java:150)
[ERROR]   	at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCBlock.accept(JCTree.java:1104)
[ERROR]   	at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:92)
[ERROR]   	at com.google.errorprone.scanner.Scanner.scan(Scanner.java:74)
[ERROR]   	at com.google.errorprone.scanner.Scanner.scan(Scanner.java:48)
[ERROR]   	at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:96)
[ERROR]   	at jdk.compiler/com.sun.source.util.TreeScanner.visitMethod(TreeScanner.java:224)
[ERROR]   	at com.google.errorprone.scanner.ErrorProneScanner.visitMethod(ErrorProneScanner.java:740)
[ERROR]   	at com.google.errorprone.scanner.ErrorProneScanner.visitMethod(ErrorProneScanner.java:150)
[ERROR]   	at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCMethodDecl.accept(JCTree.java:948)
[ERROR]   	at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:92)
[ERROR]   	at com.google.errorprone.scanner.Scanner.scan(Scanner.java:74)
[ERROR]   	at com.google.errorprone.scanner.Scanner.scan(Scanner.java:48)
[ERROR]   	at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:96)
[ERROR]   	at jdk.compiler/com.sun.source.util.TreeScanner.scan(TreeScanner.java:111)
[ERROR]   	at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:119)
[ERROR]   	at jdk.compiler/com.sun.source.util.TreeScanner.visitClass(TreeScanner.java:203)
[ERROR]   	at com.google.errorprone.scanner.ErrorProneScanner.visitClass(ErrorProneScanner.java:548)
[ERROR]   	at com.google.errorprone.scanner.ErrorProneScanner.visitClass(ErrorProneScanner.java:150)
[ERROR]   	at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCClassDecl.accept(JCTree.java:855)
[ERROR]   	at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:92)
[ERROR]   	at com.google.errorprone.scanner.Scanner.scan(Scanner.java:74)
[ERROR]   	at com.google.errorprone.scanner.Scanner.scan(Scanner.java:48)
[ERROR]   	at jdk.compiler/com.sun.source.util.TreeScanner.scan(TreeScanner.java:111)
[ERROR]   	at jdk.compiler/com.sun.source.util.TreeScanner.scanAndReduce(TreeScanner.java:119)
[ERROR]   	at jdk.compiler/com.sun.source.util.TreeScanner.visitCompilationUnit(TreeScanner.java:152)
[ERROR]   	at com.google.errorprone.scanner.ErrorProneScanner.visitCompilationUnit(ErrorProneScanner.java:560)
[ERROR]   	at com.google.errorprone.scanner.ErrorProneScanner.visitCompilationUnit(ErrorProneScanner.java:150)
[ERROR]   	at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCCompilationUnit.accept(JCTree.java:623)
[ERROR]   	at jdk.compiler/com.sun.source.util.TreePathScanner.scan(TreePathScanner.java:66)
[ERROR]   	at com.google.errorprone.scanner.Scanner.scan(Scanner.java:58)
[ERROR]   	at com.google.errorprone.scanner.ErrorProneScannerTransformer.apply(ErrorProneScannerTransformer.java:43)
[ERROR]   	at com.google.errorprone.ErrorProneAnalyzer.finished(ErrorProneAnalyzer.java:227)
[ERROR]   	at jdk.compiler/com.sun.tools.javac.api.MultiTaskListener.finished(MultiTaskListener.java:133)
[ERROR]   	at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1436)
[ERROR]   	at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.flow(JavaCompiler.java:1383)
[ERROR]   	at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:963)
[ERROR]   	at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.lambda$doCall$0(JavacTaskImpl.java:104)
[ERROR]   	at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.invocationHelper(JavacTaskImpl.java:152)
[ERROR]   	at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:100)
[ERROR]   	at jdk.compiler/com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:94)
[ERROR]   	at org.codehaus.plexus.compiler.javac.JavaxToolsCompiler.compileInProcess(JavaxToolsCompiler.java:126)
[ERROR]   	at org.codehaus.plexus.compiler.javac.JavacCompiler.performCompile(JavacCompiler.java:214)
[ERROR]   	at org.apache.maven.plugin.compiler.AbstractCompilerMojo.execute(AbstractCompilerMojo.java:1228)
[ERROR]   	at org.apache.maven.plugin.compiler.CompilerMojo.execute(CompilerMojo.java:215)
[ERROR]   	at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:126)
[ERROR]   	at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute2(MojoExecutor.java:328)
[ERROR]   	at org.apache.maven.lifecycle.internal.MojoExecutor.doExecute(MojoExecutor.java:316)
[ERROR]   	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:212)
[ERROR]   	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:174)
[ERROR]   	at org.apache.maven.lifecycle.internal.MojoExecutor.access$000(MojoExecutor.java:75)
[ERROR]   	at org.apache.maven.lifecycle.internal.MojoExecutor$1.run(MojoExecutor.java:162)
[ERROR]   	at org.apache.maven.plugin.DefaultMojosExecutionStrategy.execute(DefaultMojosExecutionStrategy.java:39)
[ERROR]   	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:159)
[ERROR]   	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:105)
[ERROR]   	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:73)
[ERROR]   	at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:53)
[ERROR]   	at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:118)
[ERROR]   	at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:261)
[ERROR]   	at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:173)
[ERROR]   	at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:101)
[ERROR]   	at org.apache.maven.cli.MavenCli.execute(MavenCli.java:903)
[ERROR]   	at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:280)
[ERROR]   	at org.apache.maven.cli.MavenCli.main(MavenCli.java:203)
[ERROR]   	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
[ERROR]   	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
[ERROR]   	at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:255)
[ERROR]   	at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:201)
[ERROR]   	at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:361)
[ERROR]   	at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:314)
[ERROR]   	at org.codehaus.classworlds.Launcher.main(Launcher.java:41)

Context

I have to work with some ancient, pre Java 5 legacy code that cannot be changed. This code necessarily uses raw types. For example, there is a class for representing a list of strings that is declared like this

public class StringList extends ArrayList {
    // ...
}

The implementation of this class guarantees that the list elements are nothing but Strings due to runtime checks. Because of this guarantee, it is safe to cast it like this

@SuppressWarnings("unchecked")
public static List<String> convert(final StringList stringList) {
    return stringList;
}

Having the convert() method analyzed by NullAway leads to the crash/stack trace mentioned above.

I use NullAway in the following setup:

  • NullAway version: 0.11.1
  • Error Prone version: 2.30.0
  • JSpecify annotations version: 1.0.0
  • Java version: Temurin 21.0.4

Known Workaround

The compiler crash won't happen if a @SuppressWarnings("NullAway") is added to the convert() method.

@SuppressWarnings({"unchecked", "NullAway"})
public static List<String> convert(final StringList stringList) {
    return stringList;
}
@msridhar
Copy link
Collaborator

msridhar commented Aug 17, 2024

Thanks for the detailed report! We missed one place where we should bail out of checking for raw types. I put a fix up in #1021.

@ahauschulte
Copy link
Author

@msridhar Thank you for taking care of this so quickly; much appreciated.

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

Successfully merging a pull request may close this issue.

2 participants