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

(bf) slice(int, int) on view buffers fails to adjust index according to primitive size

    XMLWordPrintable

    Details

    • Subcomponent:
    • Resolved In Build:
      b31
    • CPU:
      generic
    • OS:
      generic
    • Verification:
      Verified

      Backports

        Description

        ADDITIONAL SYSTEM INFORMATION :
        $ java -version
        java version "15.0.1" 2020-10-20
        $ uname -a
        Linux [redacted] 5.9.15-100.fc32.x86_64 #1 SMP Wed Dec 16 16:49:20 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux


        A DESCRIPTION OF THE PROBLEM :
        All the DirectXBuffer[US] types (beyond ByteBuffer) have a broken slice(int,int) method that fails to adjust the 'index' parameter by the primitive byte size. This leads to the wrong region being returned, and can read misaligned chars, shorts, ints, floats, doubles.

        For example:

                return new DirectCharBufferU(this,
                                                      -1,
                                                      0,
                                                      length,
                                                      length,
                                                      index, segment);

        The penultimate argument, 'index', is the 'off' parameter of the constructor, and is measured in bytes.

        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        Create a ByteBuffer, obtain a ShortBuffer view using asShortBuffer, create a slice using slice(int,int). See the example below showing the error.

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        The slice starts at the correct offset.
        ACTUAL -
        The slice starts at a partial offset.

        ---------- BEGIN SOURCE ----------
        public class BufferSliceBug
        {
            public static void main( String[] args )
            {
                class BufferKind< T extends Buffer >
                {
                    String name;
                    Function< ByteBuffer, T > asTypedBuffer;
                    ToIntFunction< T > get;
                    ObjIntConsumer< T > put;

                    BufferKind( String name, Function< ByteBuffer, T > asTypedBuffer, ToIntFunction< T > get, ObjIntConsumer< T > put )
                    {
                        this.name = name;
                        this.asTypedBuffer = asTypedBuffer;
                        this.get = get;
                        this.put = put;
                    }

                    void heapLE()
                    {
                        test( this.asTypedBuffer.apply( ByteBuffer.allocate( 32 ).order( ByteOrder.LITTLE_ENDIAN ) ) );
                    }

                    void heapBE()
                    {
                        test( this.asTypedBuffer.apply( ByteBuffer.allocate( 32 ).order( ByteOrder.BIG_ENDIAN ) ) );
                    }

                    void directLE()
                    {
                        test( this.asTypedBuffer.apply( ByteBuffer.allocateDirect( 32 ).order( ByteOrder.LITTLE_ENDIAN ) ) );
                    }

                    void directBE()
                    {
                        test( this.asTypedBuffer.apply( ByteBuffer.allocateDirect( 32 ).order( ByteOrder.BIG_ENDIAN ) ) );
                    }

                    private void test( T buffer )
                    {
                        // Fill buffer with primitives of values [0..]
                        fill( buffer );

                        // Take a slice and verify.
                        T slice = (T) buffer.slice( 1, buffer.capacity() - 1 );
                        verify( slice, 1 );
                    }

                    private void fill( T buffer )
                    {
                        int i = 0;
                        while ( buffer.hasRemaining() )
                        {
                            this.put.accept( buffer, i++ );
                        }
                        buffer.clear();
                    }

                    private void verify( T buffer, int from )
                    {
                        int i = from;
                        while ( buffer.hasRemaining() )
                        {
                            if ( this.get.applyAsInt( buffer ) != i )
                            {
                                System.out.println( "Broken : " + buffer.getClass().getSimpleName() );
                                return;
                            }
                            i++;
                        }
                        System.out.println( "Correct : " + buffer.getClass().getSimpleName() );
                    }
                }

                BufferKind< ? >[] kinds =
                {
                    new BufferKind<>( "ByteBuffer", ByteBuffer::duplicate, ByteBuffer::get, ( buffer, value ) -> buffer.put( (byte) value ) ),
                    new BufferKind<>( "ShortBuffer", ByteBuffer::asShortBuffer, ShortBuffer::get, ( buffer, value ) -> buffer.put( (short) value ) ),
                    new BufferKind<>( "IntBuffer", ByteBuffer::asIntBuffer, IntBuffer::get, IntBuffer::put ),
                    new BufferKind<>( "LongBuffer", ByteBuffer::asLongBuffer, buffer -> (int) buffer.get(), LongBuffer::put ),
                    new BufferKind<>( "FloatBuffer", ByteBuffer::asFloatBuffer, buffer -> (int) buffer.get(), FloatBuffer::put ),
                    new BufferKind<>( "DoubleBuffer", ByteBuffer::asDoubleBuffer, buffer -> (int) buffer.get(), DoubleBuffer::put ),
                    new BufferKind<>( "CharBuffer", ByteBuffer::asCharBuffer, CharBuffer::get, ( buffer, value ) -> buffer.put( (char) value ) ),
                };

                for ( BufferKind< ? > kind : kinds )
                {
                    System.out.println( kind.name );
                    kind.heapLE();
                    kind.heapBE();
                    kind.directLE();
                    kind.directBE();
                    System.out.println();
                }
            }
        }
        ---------- END SOURCE ----------

        CUSTOMER SUBMITTED WORKAROUND :
        Use Buffer.position(), Buffer.limit(), Buffer.slice() and then reset the Buffer to its original position/limit.

        FREQUENCY : always


          Attachments

            Issue Links

              Activity

                People

                Assignee:
                chegar Chris Hegarty
                Reporter:
                webbuggrp Webbug Group
                Votes:
                0 Vote for this issue
                Watchers:
                4 Start watching this issue

                  Dates

                  Created:
                  Updated:
                  Resolved: