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

MemorySegment.mismatch() wrongly returns -1 (no mismatch)

XMLWordPrintable

    • generic
    • generic

      ADDITIONAL SYSTEM INFORMATION :
      OpenJDK 20. This bug is OS-independent. It was introduced in JDK-8246095 and the code is not fixed in the latest master of openjdk


      A DESCRIPTION OF THE PROBLEM :
      AbstractMemorySegmentImpl.mismatch() assumes that any two ranges within the same MemorySegment will contain the exact same bytes. This behavior is not clearly stated in the docs, which refer to Arrays.mismatch, which makes no such assumption.

      Suppose one has a MemorySegment containing "bobrob":

      ```
          byte[] u8 = "bobrob".getBytes(StandardCharsets.UTF_8);
          var segment = MemorySegment.ofArray(u8);
      ```
      Then `MemorySegment.mismatch(segment, 0, 3, segment, 3, 6)` should return 0 as "bob" and "rob" mismatch at the first byte. The current implementation returns -1 since it assumes that any two ranges within the same segment are equal. See the first if in AbstractMemorySegmentImpl.mismatch (line 636 on master):

      ```
      if (dstImpl == srcImpl) {
          srcImpl.checkValidState();
          return -1;
      }
      ```

      Fix: the condition should instead be `dstImpl == srcImpl && srcFromOffset == dstFromOffset`.

      That `if` appeared in JDK-8246095 together with the mismatch method. Since the foreign API is in preview, it would be sensible to change the behavior to align with Arrays.mismatch() rather than changing the javadoc.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      The following code will print "m=-1" if the bug is present, where "m=0" would be the expected result from the docs.

      Note: must be run with --enable-preview JVM argument
      ```
      public static void main(String[] args) {
          byte[] u8 = "bobrob".getBytes(StandardCharsets.UTF_8);
          var segment = MemorySegment.ofArray(u8);
          long m = MemorySegment.mismatch(segment, 0, 3, segment, 3, 6);
          System.out.printf("m=%d", m);
      }
      ```

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      m=0
      (the two ranges mismatch at byte zero, relative to their starts)
      ACTUAL -
      m=-1
      (mismatch() claims the ranges have the same bytes, when they do not)

      ---------- BEGIN SOURCE ----------
      byte[] u8 = "bobrob".getBytes(StandardCharsets.UTF_8);
      var segment = MemorySegment.ofArray(u8);
      long m = MemorySegment.mismatch(segment, 0, 3, segment, 3, 6);
      assertEquals(0, m);
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Manually compare ranges calling MemorySegment.get(JAVA_BYTE, i) in a for loop.

      FREQUENCY : always


            mcimadamore Maurizio Cimadamore
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated: