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

Wrong bytecode accepted, and StackMap table generated

    XMLWordPrintable

Details

    • Bug
    • Resolution: Fixed
    • P4
    • 22
    • 22
    • core-libs

    Description

      The ClassFile API can be instructed to create an invalid code shape, which by itself is not problematic, but the StakMap generator will accept the code, and generate some (obviously wrong) Stack Map for it.

      The test is:
      ---
      /*
       * @test
       * @summary Testing Classfile stack maps generator.
       * @build testdata.*
       * @run junit WrongInputStackMapTest
       */

      import jdk.internal.classfile.*;
      import org.junit.jupiter.api.Test;

      import java.lang.constant.ClassDesc;
      import java.lang.constant.MethodTypeDesc;
      import java.lang.reflect.AccessFlag;

      /**
       * StackMapsTest
       */
      class WrongInputStackMapTest {

          @Test
          void testX() throws Exception {
              var cc = Classfile.of();
              byte[] data = cc.build(ClassDesc.of("Test"), clb -> {
                  clb.withFlags(AccessFlag.FINAL, AccessFlag.SUPER, AccessFlag.SYNTHETIC)
                     .withMethodBody("test",
                                     MethodTypeDesc.ofDescriptor("(Z)V"),
                                     Classfile.ACC_STATIC,
                                     cb -> {
                                         Label target = cb.newLabel();
                                         Label next = cb.newLabel();
                                         cb.iload(0);
                                         cb.ifeq(next);
                                         cb.constantInstruction(0.0d);
                                         cb.goto_(target);
                                         cb.labelBinding(next);
                                         cb.constantInstruction(0);
                                         cb.labelBinding(target);
                                         cb.pop();
                                     });
              });
              java.lang.invoke.MethodHandles.lookup().defineHiddenClass(data, true);
          }
      }
      ---

      This fails with:
      ---
      STARTED WrongInputStackMapTest::testX 'testX()'
      java.lang.VerifyError: Inconsistent stackmap frames at branch target 9
      Exception Details:
        Location:
          Test+0x000000007e18cc00.test(Z)V @5: goto
        Reason:
          Current frame's stack size doesn't match stackmap.
        Current Frame:
          bci: @5
          flags: { }
          locals: { integer }
          stack: { double, double_2nd }
        Stackmap Frame:
          bci: @9
          flags: { }
          locals: { integer }
          stack: { }
        Bytecode:
          0000000: 1a99 0007 0ea7 0004 0357
        Stackmap Table:
          same_frame(@8)
          same_frame(@9)

      at java.base/java.lang.ClassLoader.defineClass0(Native Method)
      at java.base/java.lang.System$2.defineClass(System.java:2394)
      at java.base/java.lang.invoke.MethodHandles$Lookup.defineHiddenClass(MethodHandles.java:2137)
      at WrongInputStackMapTest.testX(WrongInputStackMapTest.java:64)
      at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
      at java.base/java.lang.reflect.Method.invoke(Method.java:580)
      at java.base/java.util.ArrayList.forEach(ArrayList.java:1597)
      at java.base/java.util.ArrayList.forEach(ArrayList.java:1597)
      at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
      at java.base/java.lang.reflect.Method.invoke(Method.java:580)
      at java.base/java.lang.Thread.run(Thread.java:1570)
      FAILED WrongInputStackMapTest::testX 'testX()'
      ---

      While it should preferably fail before that, while generating the StackMaps. The resulting classfile is:
      ---
      Classfile /tmp/stackmap-test.class
        Last modified Nov 16, 2023; size 139 bytes
        SHA-256 checksum 0b3e034baeac4553c9ba9b0c958288689ba9f2b9bce1ff8feefe1326c5aae553
      final class Test
        minor version: 0
        major version: 66
        flags: (0x1030) ACC_FINAL, ACC_SUPER, ACC_SYNTHETIC
        this_class: #2 // Test
        super_class: #6 // java/lang/Object
        interfaces: 0, fields: 0, methods: 1, attributes: 0
      Constant pool:
        #1 = Utf8 Test
        #2 = Class #1 // Test
        #3 = Utf8 test
        #4 = Utf8 (Z)V
        #5 = Utf8 java/lang/Object
        #6 = Class #5 // java/lang/Object
        #7 = Utf8 Code
        #8 = Utf8 StackMapTable
      {
        static void test(boolean);
          descriptor: (Z)V
          flags: (0x0008) ACC_STATIC
          Code:
            stack=2, locals=1, args_size=1
               0: iload_0
               1: ifeq 8
               4: dconst_0
               5: goto 9
               8: iconst_0
               9: pop
            StackMapTable: number_of_entries = 2
              frame_type = 8 /* same */
              frame_type = 0 /* same */
      }
      ---

      Attachments

        Issue Links

          Activity

            People

              asotona Adam Sotona
              jlahoda Jan Lahoda
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: