JVM fastdebug assertion failure in nmethod::flush

XMLWordPrintable

    • generic
    • generic

      ADDITIONAL SYSTEM INFORMATION :
      - Operating system: Linux
      - Compiler/toolchain: GCC 9.5
      - Source commit: a8784a04081a11a41fe0e3bd8ab9fba6af2d3d4d (tag: jdk-17.0.18+4, branch: master)
      - Build type: fastdebug
      - Coverage: enabled (built with --enable-coverage)
      - Build environment: Linux, compiled from source with GCC 9.5

      A DESCRIPTION OF THE PROBLEM :
      - I observe a deterministic VM crash (fastdebug build) when running a slightly modified version of test/hotspot/jtreg/compiler/codecache/jmx/PeakUsageTest.java.
      - The test allocates a code blob using WhiteBox.allocateCodeBlob and later, in a finally block, calls WhiteBox.freeCodeBlob on the same address inside a loop (freeing the same blob many times).
      - Expected output: “PASS”. Actual behavior: VM aborts with an internal assertion failure in nmethod::flush:
        - assert(is_zombie() || is_osr_method()) failed: must be a zombie method
        - Location: src/hotspot/share/code/nmethod.cpp:1548
        - Problematic frame: V [libjvm.so+0x27ba414] nmethod::flush()+0x3e4
      - The crash reproduces consistently with the flags below. This suggests that repeatedly invoking WhiteBox.freeCodeBlob on an already-freed/invalid blob can drive the nmethod lifecycle into an unexpected state where nmethod::flush() runs on a non-zombie, triggering the assert. Even if the test misuses WhiteBox (double-free), the VM abort seems undesirable for WhiteBox-based testing; a safer behavior might be to make freeCodeBlob idempotent or return an error without tripping asserts.


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Same as the way to run `test/hotspot/jtreg/compiler/codecache/jmx/PeakUsageTest.java`.

      ACTUAL -
      JRE version: OpenJDK Runtime Environment (17.0.18) (build 17.0.18-internal+0-adhoc.syc.jdk17u)
          Java VM: OpenJDK 64-Bit Server VM (17.0.18-internal+0-adhoc.syc.jdk17u, mixed mode, tiered, compressed oops, compressed class ptrs, g1 gc, linux-amd64)
          Problematic frame:
          V [libjvm.so+0x5692ef] ciObjectFactory::create_new_metadata(Metadata*)+0x2f

      ---------- BEGIN SOURCE ----------
      package compiler.codecache.jmx;

      import jdk.test.whitebox.code.BlobType;

      import java.lang.management.MemoryPoolMXBean;
      import java.util.concurrent.atomic.AtomicReferenceArray;

      public class PeakUsageTest {
          private final BlobType btype;

          public PeakUsageTest(BlobType btype) {
              this.btype = btype;
          }

          public static void main(java.lang.String[] args) {
              for (BlobType btype : BlobType.getAvailable()) {
                  new PeakUsageTest(btype).runTest();
              }
          }

          protected void runTest() {
              MemoryPoolMXBean bean = btype.getMemoryPool();
              bean.resetPeakUsage();
              long addr = CodeCacheUtils.WB.allocateCodeBlob(CodeCacheUtils.ALLOCATION_SIZE, btype.id);

              int lvInt3 = -803;
              int lvInt1 = -803;
              int lvInt2 = -803;
              boolean lvBool1 = false;
              String lvStr1 = new String("asdfasf123123");
              AtomicReferenceArray<String> lvAtom1 = new AtomicReferenceArray<String>(64);
              for (int tmpi = 0; tmpi < 64; tmpi++) {
                  lvAtom1.set(tmpi, "str" + tmpi);
              }

              try {
                  long currUsage = bean.getUsage().getUsed();
                  long peakUsage = bean.getPeakUsage().getUsed();
                  CodeCacheUtils.assertEQorLTE(
                          btype,
                          currUsage,
                          peakUsage,
                          "Peak usage does not match usage after allocation for " + bean.getName());
              } finally {
                  if (addr != 0) {
                      CodeCacheUtils.WB.freeCodeBlob(addr);
                  }
              }
              bean.resetPeakUsage();
              long currUsage = bean.getUsage().getUsed();
              long peakUsage = bean.getPeakUsage().getUsed();
              CodeCacheUtils.assertEQorLTE(
                      btype,
                      currUsage,
                      peakUsage,
                      "Code cache peak usage is not equal to usage after reset for " + bean.getName());
              long addr2 = CodeCacheUtils.WB.allocateCodeBlob(CodeCacheUtils.ALLOCATION_SIZE, btype.id);

              try {
                  for (lvInt1 = 0; lvInt1 < 333; lvInt1++) {

                      currUsage = bean.getUsage().getUsed();
                      peakUsage = bean.getPeakUsage().getUsed();

                      for (lvInt2 = 0; lvInt2 < 333; lvInt2++) {
                          int tmpVar1 = lvInt1 + lvInt3;
                          int tmpVar2 = (lvInt1 * lvInt3) - lvInt1;
                          lvInt1 = tmpVar1 + tmpVar2;

                          CodeCacheUtils.assertEQorLTE(
                                  btype,
                                  currUsage,
                                  peakUsage,
                                  ("Code cache peak usage is not equal to usage after fresh "
                                                  + "allocation for ")
                                          + bean.getName());
                      }
                  }
              } finally {
                  if (addr2 != 0) {
                      for (lvInt1 = 0; lvInt1 < 333; lvInt1++) {
                          CodeCacheUtils.WB.freeCodeBlob(addr2);
                          lvBool1 = lvAtom1.compareAndSet(32, lvStr1, lvStr1);
                      }
                  }
              }
              System.out.println("PASS");
          }
      }

      ---------- END SOURCE ----------

            Assignee:
            Unassigned
            Reporter:
            Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved: