United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-6795561 : (bf) CharBuffer.subSequence() uses wrong capacity value for new buffer

Details
Type:
Bug
Submit Date:
2009-01-20
Status:
Resolved
Updated Date:
2011-02-16
Project Name:
JDK
Resolved Date:
2009-04-25
Component:
core-libs
OS:
solaris,solaris_8,linux
Sub-Component:
java.nio
CPU:
x86,sparc,generic
Priority:
P2
Resolution:
Fixed
Affected Versions:
1.4.0,6u10,6u14
Fixed Versions:

Related Reports
Backport:
Backport:
Backport:
Duplicate:
Relates:
Relates:

Sub Tasks

Description
FULL PRODUCT VERSION :
java version "1.6.0_10"
Java(TM) SE Runtime Environment (build 1.6.0_10-b33)
Java HotSpot(TM) Server VM (build 11.0-b15, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Linux tank 2.6.24-23-generic #1 SMP Thu Nov 27 18:13:46 UTC 2008 x86_64 GNU/Linux

A DESCRIPTION OF THE PROBLEM :
StringCharBuffer.subSequence(start,end) creates a new StringCharBuffer with the wrong capacity value. The current buffer's remaining() value is used as the new buffer's capacity. This causes an IndexOutOfBoundsException when the absolute value of the end index (the new buffer's limit) is greater than remaining().

Previously (before jdk6u10) the new buffer's capacity was the same as the wrapped string's length. This problem is also present in 6u11.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. javac CharBufTest.java
2. java CharBufTest

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Result: test
ACTUAL -
Exception in thread "main" java.lang.IndexOutOfBoundsException
	at java.nio.StringCharBuffer.subSequence(StringCharBuffer.java:92)
	at CharBufTest.main(CharBufTest.java:9)


REPRODUCIBILITY :
This bug can be reproduced always.

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

public class CharBufTest {
    public static void main(String[] args) {
        // Create a 15-char StringCharBuffer via CharBuffer.wrap()
        CharBuffer cb = CharBuffer.wrap("This is a test.");
        // Attempt to select the subsequence "test", starting at position=10
        cb.position(10);
        // Absolute value of end index below (10+4) is greater than remaining (5)
        CharSequence s = cb.subSequence(0, 4); // Fails on jdk6u10 and newer
        System.out.println("Result: " + s);
    }
}

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

CUSTOMER SUBMITTED WORKAROUND :
Works OK as long as absolute end index is <= remaining(). Could use slice() first to enforce this.

Release Regression From : 6u6
The above release value was the last known release where this 
bug was not reproducible. Since then there has been a regression.

                                    

Comments
EVALUATION

The submitter is correct and there is a regression since 6u10. The regression is caused by the changes for 6546113 that went into 6u10 to address problems caused by 4997655. Yes, we goofed big time here. These issues should have been caught during code review or by tests. Our plan for this issue is to fix it in jdk7 first and let it bake before doing into a jdk6 update.
                                     
2009-03-09
SUGGESTED FIX

hg diff src/share/classes/java/nio test/java/nio/Buffer/Basic.java test/java/nio/Buffer/Basic-X.java
diff -r a8d9e8cb38bb src/share/classes/java/nio/ByteBufferAs-X-Buffer.java
--- a/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java     Wed Mar 04 15:09:14 2009 +0800
+++ b/src/share/classes/java/nio/ByteBufferAs-X-Buffer.java     Mon Mar 09 13:18:24 2009 +0000
@@ -196,10 +196,12 @@ class ByteBufferAs$Type$Buffer$RW$$BO$

         if ((start < 0) || (end > len) || (start > end))
             throw new IndexOutOfBoundsException();
-        int sublen = end - start;
-        int off = offset + ((pos + start) << $LG_BYTES_PER_VALUE$);
-        assert (off >= 0);
-        return new ByteBufferAsCharBuffer$RW$$BO$(bb, -1, 0, sublen, sublen, off);
+        return new ByteBufferAsCharBuffer$RW$$BO$(bb,
+                                                  -1,
+                                                  pos + start,
+                                                  pos + end,
+                                                  capacity(),
+                                                  offset);
     }

 #end[char]
diff -r a8d9e8cb38bb src/share/classes/java/nio/Direct-X-Buffer.java
--- a/src/share/classes/java/nio/Direct-X-Buffer.java   Wed Mar 04 15:09:14 2009 +0800
+++ b/src/share/classes/java/nio/Direct-X-Buffer.java   Mon Mar 09 13:18:24 2009 +0000
@@ -412,10 +412,12 @@ class Direct$Type$Buffer$RW$$BO$

         if ((start < 0) || (end > len) || (start > end))
             throw new IndexOutOfBoundsException();
-        int sublen = end - start;
-        int off = (pos + start) << $LG_BYTES_PER_VALUE$;
-        assert (off >= 0);
-        return new DirectCharBuffer$RW$$BO$(this, -1, 0, sublen, sublen, off);
+        return new DirectCharBuffer$RW$$BO$(this,
+                                            -1,
+                                            pos + start,
+                                            pos + end,
+                                            capacity(),
+                                            offset);
     }

 #end[char]
diff -r a8d9e8cb38bb src/share/classes/java/nio/Heap-X-Buffer.java
--- a/src/share/classes/java/nio/Heap-X-Buffer.java     Wed Mar 04 15:09:14 2009 +0800
+++ b/src/share/classes/java/nio/Heap-X-Buffer.java     Mon Mar 09 13:18:24 2009 +0000
@@ -572,10 +572,13 @@ class Heap$Type$Buffer$RW$
             || (end > length())
             || (start > end))
             throw new IndexOutOfBoundsException();
-        int len = end - start;
+        int pos = position();
         return new HeapCharBuffer$RW$(hb,
-                                      -1, 0, len, len,
-                                      offset + position() + start);
+                                      -1,
+                                      pos + start,
+                                      pos + end,
+                                      capacity(),
+                                      offset);
     }

 #end[char]
diff -r a8d9e8cb38bb src/share/classes/java/nio/StringCharBuffer.java
--- a/src/share/classes/java/nio/StringCharBuffer.java  Wed Mar 04 15:09:14 2009 +0800
+++ b/src/share/classes/java/nio/StringCharBuffer.java  Mon Mar 09 13:18:24 2009 +0000
@@ -102,10 +102,12 @@ class StringCharBuffer
     public final CharBuffer subSequence(int start, int end) {
         try {
             int pos = position();
-            return new StringCharBuffer(str, -1,
+            return new StringCharBuffer(str,
+                                        -1,
                                         pos + checkIndex(start, pos),
                                         pos + checkIndex(end, pos),
-                                        remaining(), offset);
+                                        capacity(),
+                                        offset);
         } catch (IllegalArgumentException x) {
             throw new IndexOutOfBoundsException();
         }
diff -r a8d9e8cb38bb test/java/nio/Buffer/Basic-X.java
--- a/test/java/nio/Buffer/Basic-X.java Wed Mar 04 15:09:14 2009 +0800
+++ b/test/java/nio/Buffer/Basic-X.java Mon Mar 09 13:18:24 2009 +0000
@@ -366,7 +366,10 @@ public class Basic$Type$
         b.position(2);
         ck(b, b.charAt(1), 'd');
         CharBuffer c = (CharBuffer)b.subSequence(1, 4);
-        ck(b, b.subSequence(1, 4).toString().equals("def"));
+        ck(c, c.capacity(), b.capacity());
+        ck(c, c.position(), b.position()+1);
+        ck(c, c.limit(), b.position()+4);
+        ck(c, b.subSequence(1, 4).toString().equals("def"));

         // 4938424
         b.position(4);
@@ -722,6 +725,8 @@ public class Basic$Type$
         ck(b, start, b.position());
         ck(b, end, b.limit());
         ck(b, s.length(), b.capacity());
+        b.position(6);
+        ck(b, b.subSequence(0,3).toString().equals("ghi"));

         // The index, relative to the position, must be non-negative and
         // smaller than remaining().
diff -r a8d9e8cb38bb test/java/nio/Buffer/Basic.java
--- a/test/java/nio/Buffer/Basic.java   Wed Mar 04 15:09:14 2009 +0800
+++ b/test/java/nio/Buffer/Basic.java   Mon Mar 09 13:18:24 2009 +0000
@@ -25,7 +25,7 @@
  * @summary Unit test for buffers
  * @bug 4413135 4414911 4416536 4416562 4418782 4471053 4472779 4490253 4523725
  *      4526177 4463011 4660660 4661219 4663521 4782970 4804304 4938424 6231529
- *      6221101 6234263 6535542 6591971 6593946
+ *      6221101 6234263 6535542 6591971 6593946 6795561
  * @author Mark Reinhold
  */
                                     
2009-03-09



Hardware and Software, Engineered to Work Together