United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6231529 (bf) ByteBuffer.reset throws InvalidMarkException if ByteBuffer.duplicate called when mark == 0
JDK-6231529 : (bf) ByteBuffer.reset throws InvalidMarkException if ByteBuffer.duplicate called when mark == 0

Details
Type:
Bug
Submit Date:
2005-02-22
Status:
Resolved
Updated Date:
2010-07-29
Project Name:
JDK
Resolved Date:
2005-07-22
Component:
core-libs
OS:
generic
Sub-Component:
java.nio
CPU:
generic
Priority:
P3
Resolution:
Fixed
Affected Versions:
6
Fixed Versions:

Related Reports
Backport:
Backport:

Sub Tasks

Description
Error scenario:
A ByteBuffer has its mark currently set at position 0.
ByteBuffer.duplicate is used to create a duplicate ByteBuffer
from the original.  If the reset method is called on the
duplicate ByteBuffer, it throws InvalidMarkException, implying
that the mark was not set for the duplicate ByteBuffer.

Note that this problem only seems to occur if the mark was set
for position 0 when the original ByteBuffer was duplicated.

This was tested with every version of Java 1.4 that I could find
with the same results.  This includes using build 1.4.2_07-b05.

The problem could also be reproduced for 5.0 and 6.0, on both
Windows and Solaris; no attempts were made to test on other OS's
but the problem is probably OS-independent.


// ******************** START JAVA TEST CODE ********************
/**
 * Class to test using ByteBuffers.
 */
 
import java.nio.*;

class ByteBufferTest {
  
  public static void main(String args[]) {
    
    int setPosition = 0;
    ByteBuffer buf = ByteBuffer.allocateDirect(10);
    
    if (args.length > 0)
        try {setPosition = Integer.parseInt(args[0]);} catch (Exception e) {}

    System.out.println("Initializing position and mark to " + setPosition);
    buf.position(setPosition);
    buf.mark();

    ByteBuffer dup = buf.duplicate();

    try {
        buf.reset();
        System.out.println("Reset worked correctly for original buffer.");
    } catch (InvalidMarkException e) {
        System.out.println("Reset failed for original buffer.");        
    }

    try {
        dup.reset();
        System.out.println("Reset worked correctly for duplicate buffer.");
    } catch (InvalidMarkException e) {
        System.out.println("Reset failed for duplicate buffer.");        
    }

    System.out.println();
  }
}
// ******************** END JAVA TEST CODE ********************


REM ******************** START TEST BAT FILE ********************
@echo off

set JAVA_HOME=C:\j2sdk1.4.2_07

echo Compiling ...
%JAVA_HOME%\bin\javac ByteBufferTest.java


echo.
echo Running ...
%JAVA_HOME%\jre\bin\java -cp . ByteBufferTest 0
%JAVA_HOME%\jre\bin\java -cp . ByteBufferTest 1
%JAVA_HOME%\jre\bin\java -cp . ByteBufferTest 2


pause
REM ******************** END TEST BAT FILE ********************


When running the test bat file, the following output is produced:
Compiling ...

Running ...
Initializing position and mark to 0
Reset worked correctly for original buffer.
Reset failed for duplicate buffer.

Initializing position and mark to 1
Reset worked correctly for original buffer.
Reset worked correctly for duplicate buffer.

Initializing position and mark to 2
Reset worked correctly for original buffer.
Reset worked correctly for duplicate buffer.

Press any key to continue . . .
###@###.### 2005-2-22 05:31:11 GMT

                                    

Comments
EVALUATION

I believe that a similar problem will be observed with X-Buffer.asReadOnlyBuffer
when the buffer isn't read-only.

From the spec of ByteBuffer.duplicate:

  The new buffer's capacity, limit, position, and mark values will be 
  identical to those of this buffer.

When calling ByteBuffer.duplicate, we eventually end up calling the
package-private constructor in Buffer.java.

From the Buffer.java class javadoc:

  The following invariant holds for the mark, position, limit, and capacity
  values:

    0 <= mark <= position <= limit <= capacity

  A newly-created buffer always has a position of zero and a mark that is 
  undefined. 

It looks like a minor modification is needed to the constructor in Buffer.java
to handle the case of mark == 0:

  Buffer(int mark, int pos, int lim, int cap) {   
        [ ... ]
        if (mark > 0) {          // change to (mark >= 0) 
            if (mark > pos) 
                throw new IllegalArgumentException(); 
            this.mark = mark; 
        }
  }

I don't believe that 0 is ever used in the buffer code to indicate an error 
condition or an unset mark, but close examination of all of the code in 
java.nio.*Buffer* should be made before this change is applied.

###@###.### 2005-2-22 21:12:25 GMT
                                     
2005-02-22



Hardware and Software, Engineered to Work Together