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

(bf) Bulk put not consistent with API docs when buffers overlap

XMLWordPrintable

    • generic
    • generic

      A DESCRIPTION OF THE PROBLEM :
      The documentation for put(IntBuffer src) in IntBuffer states that it is equivalent to looping through the source buffer using get() and sequentially putting the results into the destination buffer. However, this is not true when:
      * the source buffer was obtained from the parent buffer using slice(); and
      * the position of the destination buffer is after the point that the source buffer begins; and
      * the point at which the source buffer ends is beyond the position of the destination buffer at the time the method is invoked.

      Note: This was tested with IntBuffer, but probably exists in other subclasses of Buffer also.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Allocate an IntBuffer of size 6 (call this dst), fill it with sequential integers, then set its position to 1 and limit to 5, and take a slice (call this src). Set the dst buffer's position to 2 and limit to 6, then put src into dst with put(IntBuffer). Set the dst buffer's position back to 0 and use get() to check its contents - they will not be equivalent to using the supposedly-equivalent loop given in the API documentation.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      Based on the API documentation, the contents of dst after following the steps above should be {0, 1, 1, 1, 1, 1}, as the same value is repeatedly written read from src, then put into dst at the position for the subsequent read from src.

      (this is unlikely to be the *desired* result in most realistic cases so the best solution may be to amend the documentation rather than to change the behaviour)
      ACTUAL -
      The contents of dst will instead be {0, 1, 1, 2, 3, 4}; this would be the result of copying the contents of src to a separate memory location, then copying it from that location into dst.

      ---------- BEGIN SOURCE ----------
      import java.nio.IntBuffer;

      public class BufferBugTester {
      public static void main(String[] args) {
      System.out.println("Running test with put(src): ");
      bufferSliceCopyTest(false);
      System.out.println();
      System.out.println("Running test with looped put(src.get()): ");
      bufferSliceCopyTest(true);
      }

      public static void bufferSliceCopyTest(boolean useExplicitLoop) {

      IntBuffer dst = IntBuffer.allocate(6);
      System.out.println("\tInitialising buffer:");
      for (int i = 0; dst.hasRemaining(); i++) {
      dst.put(i);
      System.out.println("\t\t" + i);
      }
      dst.position(1).limit(5);
      IntBuffer src = dst.slice();
      dst.position(2).limit(6);
      if (useExplicitLoop)
      while (src.hasRemaining()) {
      dst.put(src.get());
      }
      else {
      dst.put(src);
      }
      dst.position(0);
      System.out.println("\tResult:");
      while (dst.hasRemaining()) {
      System.out.println("\t\t" + dst.get());
      }
      }
      }

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

      CUSTOMER SUBMITTED WORKAROUND :
      In practice a workaround is unlikely to be needed, as the monolithic copy behaviour is likely to be the desired result in most cases, and presumably it is also considerably faster on large buffers. However, the API documentation should be changed to either make this a defined behaviour, or to explicitly state that the result is undefined. It would also be prudent to check whether the function uses a piecewise copy at large buffer sizes.

      FREQUENCY : always


            bpb Brian Burkhalter
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: