Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8322040

Missing array bounds check in ClassReader.parameter

    XMLWordPrintable

Details

    • b03

    Backports

      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)

        Attachments

          Issue Links

            Activity

              People

                cushon Liam Miller-Cushon
                cushon Liam Miller-Cushon
                Votes:
                0 Vote for this issue
                Watchers:
                5 Start watching this issue

                Dates

                  Created:
                  Updated:
                  Resolved: