JDK-8322040 : Missing array bounds check in ClassReader.parameter
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 11.0.23,17.0.11,21.0.2,22
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2023-12-13
  • Updated: 2024-01-08
  • Resolved: 2023-12-15
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 21 JDK 23
21-pool-oracleUnresolved 23 b03Fixed
Related Reports
Relates :  
Relates :  
Description
When javac reads a MethodParameters attribute with fewer entries than there are method parameters, it does not do a bounds check before reading from the array parameterNameIndicesMp here [1]. Note that there is a corresponding bounds check for parameterNameIndicesLvt below that code.

The ArrayIndexOutOfBounds exception is handled by ClassReader [2] and results in a bad.class.file error.

I noticed this while debugging a crash for a class that had ended up in a bad state, and I think the root cause is that the class is getting 'half completed' before MethodParameter attribute handling crashes, and then the compilation handles the exception and continues with the class file in a bad state.

[1] https://github.com/openjdk/jdk/blob/cf948548c390c42ca63525d41a9d63ff31349c3a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java#L2805-L2807

[2] https://github.com/openjdk/jdk/blob/cf948548c390c42ca63525d41a9d63ff31349c3a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java#L3108

---

I found the following crash while try to produce a repro, which is slightly different than the original crash I found:

```
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import java.util.Set;

@SupportedAnnotationTypes("*")
public class P extends AbstractProcessor {
  @Override
  public SourceVersion getSupportedSourceVersion() {
    return SourceVersion.latestSupported();
  }

  @Override
  public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
    processingEnv
        .getMessager()
        .printMessage(
            Diagnostic.Kind.NOTE,
            processingEnv
                .getElementUtils()
                .getTypeElement("T.I")
                .getEnclosedElements()
                .toString());
    return false;
  }
}
```

```
import java.nio.file.Files;
import java.nio.file.Paths;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class TDump implements Opcodes {
  public static void main(String[] args) throws Exception {
    Files.write(Paths.get("T.class"), dump());
  }

  public static byte[] dump() throws Exception {

    ClassWriter classWriter = new ClassWriter(0);
    MethodVisitor methodVisitor;

    classWriter.visit(V19, ACC_SUPER, "T", null, "java/lang/Object", null);

    classWriter.visitSource("T.java", null);

    classWriter.visitNestMember("T$I");

    classWriter.visitInnerClass("T$I", "T", "I", 0);

    {
      methodVisitor = classWriter.visitMethod(0, "<init>", "()V", null, null);
      methodVisitor.visitCode();
      Label label0 = new Label();
      methodVisitor.visitLabel(label0);
      methodVisitor.visitLineNumber(1, label0);
      methodVisitor.visitVarInsn(ALOAD, 0);
      methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
      methodVisitor.visitInsn(RETURN);
      methodVisitor.visitMaxs(1, 1);
      methodVisitor.visitEnd();
    }
    {
      methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_STATIC, "f", "(II)V", null, null);
      methodVisitor.visitParameter("x", 0);
      methodVisitor.visitCode();
      Label label0 = new Label();
      methodVisitor.visitLabel(label0);
      methodVisitor.visitLineNumber(3, label0);
      methodVisitor.visitInsn(RETURN);
      methodVisitor.visitMaxs(0, 2);
      methodVisitor.visitEnd();
    }
    classWriter.visitEnd();

    return classWriter.toByteArray();
  }
}
```

```
class T {
  public static void f(int x, int y) {
  }

  class I {}
}
```

javac -cp asm-9.5.jar:asm-util-9.5.jar TDump.java T.java P.java
java -cp asm-9.5.jar:asm-util-9.5.jar:. TDump
javac -parameters -processor P T.I
...
An exception has occurred in the compiler (22-internal). Please file a bug against the Java compiler via the Java bug reporting page (https://bugreport.java.com) after checking the Bug Database (https://bugs.java.com) for duplicates. Include your program, the following diagnostic, and the parameters passed to the Java compiler in your report. Thank you.
java.lang.ClassCastException: class com.sun.tools.javac.comp.Resolve$BadClassFileError cannot be cast to class com.sun.tools.javac.code.Symbol$ClassSymbol (com.sun.tools.javac.comp.Resolve$BadClassFileError and com.sun.tools.javac.code.Symbol$ClassSymbol are in module jdk.compiler of loader 'app')
	at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1255)
	at jdk.compiler/com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:946)
	at jdk.compiler/com.sun.tools.javac.main.Main.compile(Main.java:319)
	at jdk.compiler/com.sun.tools.javac.main.Main.compile(Main.java:178)
	at jdk.compiler/com.sun.tools.javac.Main.compile(Main.java:66)
	at jdk.compiler/com.sun.tools.javac.Main.main(Main.java:52)
Comments
A pull request was submitted for review. URL: https://git.openjdk.org/jdk21u-dev/pull/74 Date: 2023-12-19 16:47:28 +0000
19-12-2023

Fix Request JDK 21u This fixes a missing array bounds check introduced by JDK-8292275, and which was leading to a crash in specific situations after the changes introduced by JDK-8225377. The fix applied cleanly. The test required updating due to changes in the Class-File API. The modified test fails without the patch, and passes with it.
19-12-2023

Fix Request JDK 22u This fixes a missing array bounds check introduced by JDK-8292275, and which was leading to a crash in specific situations after the changes introduced by JDK-8225377. The fix applied cleanly. The test required updating due to changes in the Class-File API. The modified test fails without the patch, and passes with it.
19-12-2023

A pull request was submitted for review. URL: https://git.openjdk.org/jdk22u/pull/4 Date: 2023-12-19 16:47:29 +0000
19-12-2023

Thanks ~shade, The root cause I found with the missing bounds check on `parameterNameIndicesMp` affects 21 and later, `parameterNameIndicesMp` was added in 21 for JDK-8292275: https://github.com/openjdk/jdk/commit/b3dbf28bc0614bee2f7137af95389134155c9511#diff-23a8d62238ad3bc7231f693927b6af76a1f7a1c947456eb443545227e586fb04R2488 I haven't been able to come up with a realistic repro for that crash, but I also don't see downsides to proactively backporting to 21. The NPE in 'interfaces_field' is supposed to be impossible, by the time TypeAnnotationSymbolVisitor sees a class symbol that field should have been filled in. It's possible that there are other related error recovery bugs in this area that could lead to symbols ending up in a bad state, and have similar symptoms.
19-12-2023

I am provisionally adding the affected versions from JDK-8225377, since it affects the code added there. This needs more investigation for the impact on update releases.
19-12-2023

Changeset: 20de541b Author: Liam Miller-Cushon <cushon@openjdk.org> Date: 2023-12-15 10:16:35 +0000 URL: https://git.openjdk.org/jdk/commit/20de541b1304b4dc3a385f8a78f1215da237e4aa
15-12-2023

A pull request was submitted for review. URL: https://git.openjdk.org/jdk/pull/17097 Date: 2023-12-13 22:57:04 +0000
13-12-2023

The stack trace for the original crash I saw was the following. That crash is occurring in code added for https://bugs.openjdk.org/browse/JDK-8225377. I wasn't able to minimize the crash, and there were a few unusual things going on in that compilation including a custom argument to --system that contained an invalid MethodParameters attribute, and eventually lead me to the ArrayIndexOutOfBounds issue discussed above. I currently do not think JDK-8225377 is the root cause of this crash, and I also don't think this crash will be very common because it requires both the invalid method parameters attribute and a specific error recovery scenario. Exception: java.lang.NullPointerException: Cannot invoke "com.sun.tools.javac.util.List.iterator()" because "t.interfaces_field" is null; java.lang.NullPointerException: Cannot invoke "com.sun.tools.javac.util.List.iterator()" because "t.interfaces_field" is null at jdk.compiler/com.sun.tools.javac.jvm.ClassReader$TypeAnnotationSymbolVisitor.visitClassSymbol(ClassReader.java:2300) at jdk.compiler/com.sun.tools.javac.jvm.ClassReader$TypeAnnotationSymbolVisitor.visitClassSymbol(ClassReader.java:2286) at jdk.compiler/com.sun.tools.javac.code.Symbol$ClassSymbol.accept(Symbol.java:1585) at jdk.compiler/com.sun.tools.javac.code.Types$DefaultSymbolVisitor.visit(Types.java:4930) at jdk.compiler/com.sun.tools.javac.jvm.ClassReader.addTypeAnnotationsToSymbol(ClassReader.java:2283) 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:682) at jdk.compiler/com.sun.tools.javac.code.Symbol$ClassSymbol.complete(Symbol.java:1418) at jdk.compiler/com.sun.tools.javac.code.Symbol.apiComplete(Symbol.java:688) at jdk.compiler/com.sun.tools.javac.code.Symbol$TypeSymbol.getEnclosedElements(Symbol.java:859) at jdk.compiler/com.sun.tools.javac.code.Symbol$TypeSymbol.getEnclosedElements(Symbol.java:797)
13-12-2023