JDK-8359336 : javac crashes with NPE while iterating params of MethodSymbol
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 21.0.8
  • Priority: P2
  • Status: Open
  • Resolution: Unresolved
  • Submitted: 2025-06-12
  • Updated: 2025-06-30
Related Reports
Causes :  
Relates :  
Relates :  
Description
In our prerelease testing we see an issue with javac / javadoc.

P2 because it seems to be a regression in 21.0.8 to be delivered in about 4 weeks. 21.0.8 had several backports to javac: [21.0.8 javac issues|https://bugs.openjdk.org/browse/JDK-8354893?filter=47405&jql=(issue%20in%20linked-subquery(%22issue%20in%20linked-subquery(%5C%22issue%20in%20linked-subquery(%5C%5C%5C%22fixVersion%20in%20(21.0.8)%20AND%20status%20in%20(Resolved%2C%20Closed)%20AND%20Resolution%20not%20in%20(%5C%5C%5C%5C%5C%5C%5C%22Won%27t%20Fix%5C%5C%5C%5C%5C%5C%5C%22)%5C%5C%5C%22%2C%20backport%2C%20inward)%5C%22%2C%20backport%2C%20outward)%20AND%20fixVersion%20in%20(21.0.8)%22%2C%20backport%2C%20inward)%20OR%20fixVersion%20in%20(21.0.8)%20AND%20status%20in%20(Resolved%2C%20Closed)%20AND%20Resolution%20not%20in%20(%22Won%27t%20Fix%22)%20AND%20issue%20not%20in%20linked-subquery(%22issue%20in%20linked-subquery(%5C%22fixVersion%20in%20(21.0.8)%5C%22%2C%20backport%2C%20inward)%22%2C%20backport%2C%20outward))%20%20AND%20type%20!%3D%20CSR%20AND%20labels%20not%20in%20(release-note%2C%20testbug%2C%20noreg-self%2C%20testonly%2C%20test-only)%20%20AND%20subcomponent%20in%20(javac)%20ORDER%20BY%20id%20DESC]

The failing code was introduced by JDK-8341779.

The stack trace we see is 

 java.lang.NullPointerException: Cannot invoke "com.sun.tools.javac.util.List.iterator()" because "s.params" is null
                at jdk.compiler/com.sun.tools.javac.jvm.ClassReader$TypeAnnotationSymbolVisitor.visitMethodSymbol(ClassReader.java:2333)
                at jdk.compiler/com.sun.tools.javac.jvm.ClassReader$TypeAnnotationSymbolVisitor.visitMethodSymbol(ClassReader.java:2289)
                at jdk.compiler/com.sun.tools.javac.code.Symbol$MethodSymbol.accept(Symbol.java:2305)
                at jdk.compiler/com.sun.tools.javac.code.Types$DefaultSymbolVisitor.visit(Types.java:4927)
                at jdk.compiler/com.sun.tools.javac.jvm.ClassReader.addTypeAnnotationsToSymbol(ClassReader.java:2278)
                at jdk.compiler/com.sun.tools.javac.jvm.ClassReader$TypeAnnotationCompleter.run(ClassReader.java:2261)
                at jdk.compiler/com.sun.tools.javac.comp.Annotate.flush(Annotate.java:191)
                at jdk.compiler/com.sun.tools.javac.code.ClassFinder.complete(ClassFinder.java:322)
                at jdk.compiler/com.sun.tools.javac.code.Symbol.complete(Symbol.java:683)
                at jdk.compiler/com.sun.tools.javac.code.Symbol$ClassSymbol.complete(Symbol.java:1452)
                at jdk.compiler/com.sun.tools.javac.code.Symbol.apiComplete(Symbol.java:689)
                at jdk.compiler/com.sun.tools.javac.code.Symbol$TypeSymbol.getEnclosedElements(Symbol.java:860)
                at jdk.compiler/com.sun.tools.javac.code.Symbol$ClassSymbol.getEnclosedElements(Symbol.java:1417)
                at jdk.compiler/com.sun.tools.javac.code.Symbol$ClassSymbol.getEnclosedElements(Symbol.java:1260)
                at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.util.Utils.getItems0(Utils.java:1782)
                at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.util.Utils.recursiveGetItems(Utils.java:1763)
                at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.util.Utils.recursiveGetItems(Utils.java:1766)
                at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.util.Utils.getItems(Utils.java:1745)
                at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.util.Utils.getAllClassesUnfiltered(Utils.java:1678)
                at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.builders.SerializedFormBuilder.buildPackageSerializedForm(SerializedFormBuilder.java:171)
                at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.builders.SerializedFormBuilder.buildSerializedFormSummaries(SerializedFormBuilder.java:158)
                at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.builders.SerializedFormBuilder.buildSerializedForm(SerializedFormBuilder.java:141)
                at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.builders.SerializedFormBuilder.build(SerializedFormBuilder.java:129)
                at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.AbstractDoclet.generateOtherFiles(AbstractDoclet.java:228)
                at jdk.javadoc/jdk.javadoc.internal.doclets.formats.html.HtmlDoclet.generateOtherFiles(HtmlDoclet.java:215)
                at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.AbstractDoclet.startGeneration(AbstractDoclet.java:213)
                at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.AbstractDoclet.run(AbstractDoclet.java:110)
                at jdk.javadoc/jdk.javadoc.doclet.StandardDoclet.run(StandardDoclet.java:104)
                at jdk.javadoc/jdk.javadoc.internal.tool.Start.parseAndExecute(Start.java:575)
                at jdk.javadoc/jdk.javadoc.internal.tool.Start.begin(Start.java:398)
                at jdk.javadoc/jdk.javadoc.internal.tool.Start.begin(Start.java:347)
                at jdk.javadoc/jdk.javadoc.internal.tool.Main.execute(Main.java:57)
                at jdk.javadoc/jdk.javadoc.internal.tool.Main.main(Main.java:46)


Comments
With debug printing https://github.com/SAP/SapMachine/commit/020ef98e17c2fa8b95dd46cee3cbfbe4f3b69bf6 we get below output. OutboundSyncJobStateAggregatorUnitTest is a groovy file. Documentation for the class tested, OutboundSyncJobStateAggregator, can be found in the internet. com.sun.tools.javac.code.ClassFinder$BadClassFile: bad class file:.../apidoc/classes/de/hybris/platform/outboundsync/job/impl/OutboundSyncJobStateAggregatorUnitTest$EventThread.class bad RuntimeInvisibleParameterAnnotations attribute: EventThread(de.hybris.platform.outboundsync.job.impl.OutboundSyncJob,de.hybris.platform.outboundsync.events.OutboundSyncEvent) Please remove or make sure it appears in the correct subdirectory of the classpath. at jdk.compiler/com.sun.tools.javac.jvm.ClassReader.badClassFile(ClassReader.java:330) at jdk.compiler/com.sun.tools.javac.jvm.ClassReader.badClassFile(ClassReader.java:321) at jdk.compiler/com.sun.tools.javac.jvm.ClassReader.setParameters(ClassReader.java:2801) at jdk.compiler/com.sun.tools.javac.jvm.ClassReader.readMethod(ClassReader.java:2664) at jdk.compiler/com.sun.tools.javac.jvm.ClassReader.readClass(ClassReader.java:2979) at jdk.compiler/com.sun.tools.javac.jvm.ClassReader.readClassBuffer(ClassReader.java:3070) at jdk.compiler/com.sun.tools.javac.jvm.ClassReader.readClassFile(ClassReader.java:3094) at jdk.compiler/com.sun.tools.javac.code.ClassFinder.fillIn(ClassFinder.java:373) at jdk.compiler/com.sun.tools.javac.code.ClassFinder.complete(ClassFinder.java:302) at jdk.compiler/com.sun.tools.javac.code.Symbol.complete(Symbol.java:683) at jdk.compiler/com.sun.tools.javac.code.Symbol$ClassSymbol.complete(Symbol.java:1452) at jdk.compiler/com.sun.tools.javac.code.Symbol.apiComplete(Symbol.java:689) at jdk.compiler/com.sun.tools.javac.code.Symbol$TypeSymbol.getEnclosedElements(Symbol.java:860) at jdk.compiler/com.sun.tools.javac.code.Symbol$ClassSymbol.getEnclosedElements(Symbol.java:1417) at jdk.compiler/com.sun.tools.javac.code.Symbol$ClassSymbol.getEnclosedElements(Symbol.java:1260) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.util.Utils.getItems0(Utils.java:1782) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.util.Utils.recursiveGetItems(Utils.java:1763) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.util.Utils.recursiveGetItems(Utils.java:1766) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.util.Utils.getItems(Utils.java:1745) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.util.Utils.getAllClassesUnfiltered(Utils.java:1678) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.builders.SerializedFormBuilder.buildPackageSerializedForm(SerializedFormBuilder.java:171) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.builders.SerializedFormBuilder.buildSerializedFormSummaries(SerializedFormBuilder.java:158) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.builders.SerializedFormBuilder.buildSerializedForm(SerializedFormBuilder.java:141) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.builders.SerializedFormBuilder.build(SerializedFormBuilder.java:129) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.AbstractDoclet.generateOtherFiles(AbstractDoclet.java:228) at jdk.javadoc/jdk.javadoc.internal.doclets.formats.html.HtmlDoclet.generateOtherFiles(HtmlDoclet.java:215) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.AbstractDoclet.startGeneration(AbstractDoclet.java:213) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.AbstractDoclet.run(AbstractDoclet.java:110) at jdk.javadoc/jdk.javadoc.doclet.StandardDoclet.run(StandardDoclet.java:104) at jdk.javadoc/jdk.javadoc.internal.tool.Start.parseAndExecute(Start.java:575) at jdk.javadoc/jdk.javadoc.internal.tool.Start.begin(Start.java:398) at jdk.javadoc/jdk.javadoc.internal.tool.Start.begin(Start.java:347) at jdk.javadoc/jdk.javadoc.internal.tool.Main.execute(Main.java:57) at jdk.javadoc/jdk.javadoc.internal.tool.Main.main(Main.java:46) Analyse JDK-8359336 (2) Symbol name: <init> owner: EventThread toString: EventThread(de.hybris.platform.outboundsync.job.impl.OutboundSyncJob,de.hybris.platform.outboundsync.events.OutboundSyncEvent) owner.toString: de.hybris.platform.outboundsync.job.impl.OutboundSyncJobStateAggregatorUnitTest.EventThread Analyse JDK-8359336 Symbol name: <init> owner: EventThread toString: EventThread(de.hybris.platform.outboundsync.job.impl.OutboundSyncJob,de.hybris.platform.outboundsync.events.OutboundSyncEvent) owner.toString: de.hybris.platform.outboundsync.job.impl.OutboundSyncJobStateAggregatorUnitTest.EventThread error: An internal exception has occurred. (java.lang.NullPointerException: Cannot invoke "com.sun.tools.javac.util.List.iterator()" because "s.params" is null) Please file a bug against the javadoc tool via the Java bug reporting page (https://bugreport.java.com) after checking the Bug Database (https://bugs.java.com) for duplicates. Include error messages and the following diagnostic in your report. Thank you. java.lang.NullPointerException: Cannot invoke "com.sun.tools.javac.util.List.iterator()" because "s.params" is null at jdk.compiler/com.sun.tools.javac.jvm.ClassReader$TypeAnnotationSymbolVisitor.visitMethodSymbol(ClassReader.java:2349) at jdk.compiler/com.sun.tools.javac.jvm.ClassReader$TypeAnnotationSymbolVisitor.visitMethodSymbol(ClassReader.java:2295) at jdk.compiler/com.sun.tools.javac.code.Symbol$MethodSymbol.accept(Symbol.java:2305) at jdk.compiler/com.sun.tools.javac.code.Types$DefaultSymbolVisitor.visit(Types.java:4927) at jdk.compiler/com.sun.tools.javac.jvm.ClassReader.addTypeAnnotationsToSymbol(ClassReader.java:2284) at jdk.compiler/com.sun.tools.javac.jvm.ClassReader$TypeAnnotationCompleter.run(ClassReader.java:2266) at jdk.compiler/com.sun.tools.javac.comp.Annotate.flush(Annotate.java:191) at jdk.compiler/com.sun.tools.javac.code.ClassFinder.complete(ClassFinder.java:322) at jdk.compiler/com.sun.tools.javac.code.Symbol.complete(Symbol.java:683) at jdk.compiler/com.sun.tools.javac.code.Symbol$ClassSymbol.complete(Symbol.java:1452) at jdk.compiler/com.sun.tools.javac.code.Symbol.apiComplete(Symbol.java:689) at jdk.compiler/com.sun.tools.javac.code.Symbol$TypeSymbol.getEnclosedElements(Symbol.java:860) at jdk.compiler/com.sun.tools.javac.code.Symbol$ClassSymbol.getEnclosedElements(Symbol.java:1417) at jdk.compiler/com.sun.tools.javac.code.Symbol$ClassSymbol.getEnclosedElements(Symbol.java:1260) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.util.Utils.getItems0(Utils.java:1782) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.util.Utils.recursiveGetItems(Utils.java:1763) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.util.Utils.recursiveGetItems(Utils.java:1766) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.util.Utils.getItems(Utils.java:1745) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.util.Utils.getAllClassesUnfiltered(Utils.java:1678) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.builders.SerializedFormBuilder.buildPackageSerializedForm(SerializedFormBuilder.java:171) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.builders.SerializedFormBuilder.buildSerializedFormSummaries(SerializedFormBuilder.java:158) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.builders.SerializedFormBuilder.buildSerializedForm(SerializedFormBuilder.java:141) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.builders.SerializedFormBuilder.build(SerializedFormBuilder.java:129) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.AbstractDoclet.generateOtherFiles(AbstractDoclet.java:228) at jdk.javadoc/jdk.javadoc.internal.doclets.formats.html.HtmlDoclet.generateOtherFiles(HtmlDoclet.java:215) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.AbstractDoclet.startGeneration(AbstractDoclet.java:213) at jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.AbstractDoclet.run(AbstractDoclet.java:110) at jdk.javadoc/jdk.javadoc.doclet.StandardDoclet.run(StandardDoclet.java:104) at jdk.javadoc/jdk.javadoc.internal.tool.Start.parseAndExecute(Start.java:575) at jdk.javadoc/jdk.javadoc.internal.tool.Start.begin(Start.java:398) at jdk.javadoc/jdk.javadoc.internal.tool.Start.begin(Start.java:347) at jdk.javadoc/jdk.javadoc.internal.tool.Main.execute(Main.java:57) at jdk
30-06-2025

I think there are a couple of options for fixing this: (1) Backport JDK-8334870, which resolves the root cause of the crash. That change has some compatibility impact to which class files javac accepts, and requires a CSR. I have a draft in https://github.com/openjdk/jdk21u-dev/pull/1930/files (2) Do a more targeted fix so these class files are rejects cleanly instead of crashing, doing something like the draft in https://github.com/openjdk/jdk21u-dev/pull/1929
27-06-2025

Fixed in JDK 24 by JDK-8334870.
26-06-2025

I have attached a repro that produces a similar crash. I'll start cleaning the repro up into a regression test, and write this up more fully tomorrow. With 21u-dev at https://github.com/openjdk/jdk21u-dev/commit/d272701377edca8352ecc96db119884accd4540f, I get: $ java --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED --add-exports=java.base/jdk.internal.classfile=ALL-UNNAMED --add-exports=java.base/jdk.internal.classfile.attribute=ALL-UNNAMED D.java ... Exception in thread "main" java.lang.NullPointerException: Cannot invoke "com.sun.tools.javac.util.List.iterator()" because "s.params" is null at jdk.compiler/com.sun.tools.javac.jvm.ClassReader$TypeAnnotationSymbolVisitor.visitMethodSymbol(ClassReader.java:2339) at jdk.compiler/com.sun.tools.javac.jvm.ClassReader$TypeAnnotationSymbolVisitor.visitMethodSymbol(ClassReader.java:2295) at jdk.compiler/com.sun.tools.javac.code.Symbol$MethodSymbol.accept(Symbol.java:2305) at jdk.compiler/com.sun.tools.javac.code.Types$DefaultSymbolVisitor.visit(Types.java:4927) at jdk.compiler/com.sun.tools.javac.jvm.ClassReader.addTypeAnnotationsToSymbol(ClassReader.java:2284) at jdk.compiler/com.sun.tools.javac.jvm.ClassReader$TypeAnnotationCompleter.run(ClassReader.java:2266) at jdk.compiler/com.sun.tools.javac.comp.Annotate.flush(Annotate.java:191) at jdk.compiler/com.sun.tools.javac.code.ClassFinder.complete(ClassFinder.java:322) With that repro, a RuntimeVisibleParameterAnnotationsAttribute with a different number of annotations than the number of parameters triggers an AIOOBE in ClassReader.setParameters when an enclosing class is being completed, and leaves things in a bad state where the parameters for the MethodSymbol never get filled in, and then attaching the type annotations crashes. Adding an array bounds check to avoid the AIOOBE (and letting a badClassFile exception be thrown instead) avoids the crash: diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java index 1371323531e..a854df6b9e5 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -2752,16 +2752,16 @@ public class ClassReader { for (Type t: sym.type.getParameterTypes()) { VarSymbol param = parameter(nameIndexMp, nameIndexLvt, t, sym, paramNames); params.append(param); - if (parameterAnnotations != null) { + if (parameterAnnotations != null && annotationIndex < parameterAnnotations.length) { ParameterAnnotations annotations = parameterAnnotations[annotationIndex]; if (annotations != null && annotations.proxies != null && !annotations.proxies.isEmpty()) { annotate.normal(new AnnotationCompleter(param, annotations.proxies)); } + annotationIndex++; } nameIndexLvt += Code.width(t); nameIndexMp++; - annotationIndex++; } if (parameterAnnotations != null && parameterAnnotations.length != annotationIndex) { throw badClassFile("bad.runtime.invisible.param.annotations", sym);
26-06-2025

A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk21u-dev/pull/1916 Date: 2025-06-23 17:51:06 +0000
23-06-2025

In order to develop a reproducer it might be helpful to get the output of javadoc with -verbose flag. This (hopefully) will show broken annotation as well as a list of imports, which can be used to reconstruct import (possibly implicit import) chain and classpath problems.
23-06-2025

Hi Liam, It's our SapMachine build which is based on the current status of jdk21u (not jdk21u-dev). SapMachine has slight modifications, like some more print outs to the hs_err file. But javac and javadoc are identical. We are in contact with the application team to get a repro case.
12-06-2025

I'm still suspicious of an interaction with JDK-8334870, maybe similar to JDK-8322040. I tried various attempts to repro with the javac API and with annotations processors, but could reproduce these symptoms with the partially completed symbols, I just get 'bad class file' diagnostics. It's possible the way javadoc interacts with javac is different than the approach I was using, or maybe that's the wrong track. [~goetz] would it be possible to share a repro, or any more details about the specific build where this was encountered?
12-06-2025

I wonder if this could be an interaction with JDK-8334870, or a related issue. MethodSymbol.params should be set to a non-null values in ClassReader.setParameters: https://github.com/openjdk/jdk21u-dev/blob/8a6ea1b36909479b06f1ed273ed2c0dd8e34e364/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java#L2750-L2764 But there are situations where setParameters could crash out before it fills in the parameters. The stack trace shows Symbol.apiComplete, and in those paths the implementation will try to recover from crashes involving bad class files or completion failures, so execution could continue to alter try to attach the type annotations to a partially created MethodSymbol with null params. I don't have a repro yet. If that theory is correct, backporting JDK-8334870 may not be a good option (it isn't a trivial fix, it had a CSR). There may be more limited fixes, if the theory is correct it would be sufficient to just add a null check. Lastly if it's necessary to remove JDK-8341779 from 21.0.8, rather than backing out all of the related changes it would be possible to just disable this line, that is the only entry point into the backported logic: https://github.com/openjdk/jdk/blob/8d33ea7395e5dd504b899d8972617f6696546d84/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java#L2319C17-L2319C43
12-06-2025

It works with 21.0.7. The system used for testing is huge and as you assumed unfortunately does not work on Java 22 or later.
12-06-2025

[~goetz] JDK-8225377 is in JDK 22 and better. I take it the application team is not ready to test whether or not the same issue exists with a newer JDK release than JDK 21? It seems strange for it to be a JDK 21-only problem.
12-06-2025