SUGGESTED FIX
--- /u/martin/ws/mustang/src/share/classes/java/lang/StringCoding.java 2004-08-27 15:53:50.956130000 -0700
+++ /u/martin/ws/nio/src/share/classes/java/lang/StringCoding.java 2004-09-14 22:21:24.156289000 -0700
@@ -76,6 +76,12 @@
return tca;
}
+ private static int scale(int len, float expansionFactor) {
+ // We need to perform double, not float, arithmetic; otherwise
+ // we lose low order bits when len is larger than 2**24.
+ return (int)(len * (double)expansionFactor);
+ }
+
private static Charset lookupCharset(String csn) {
if (Charset.isSupported(csn)) {
try {
@@ -173,7 +179,7 @@
}
char[] decode(byte[] ba, int off, int len) {
- int en = (int)(cd.maxCharsPerByte() * len);
+ int en = scale(len, cd.maxCharsPerByte());
char[] ca = new char[en];
if (len == 0)
return ca;
@@ -324,7 +330,7 @@
}
byte[] encode(char[] ca, int off, int len) {
- int en = (int)(ce.maxBytesPerChar() * len);
+ int en = scale(len, ce.maxBytesPerChar());
byte[] ba = new byte[en];
if (len == 0)
return ba;
--- /u/martin/ws/mustang/src/share/classes/sun/nio/cs/ext/JISAutoDetect.java 2004-08-27 16:00:37.276131000 -0700
+++ /u/martin/ws/nio/src/share/classes/sun/nio/cs/ext/JISAutoDetect.java 2004-09-14 22:21:25.293210000 -0700
@@ -138,7 +138,9 @@
if (! dst.hasRemaining())
return CoderResult.OVERFLOW;
- int cbufsiz = (int) (src.limit() * maxCharsPerByte());
+ // We need to perform double, not float, arithmetic; otherwise
+ // we lose low order bits when src is larger than 2**24.
+ int cbufsiz = (int)(src.limit() * (double)maxCharsPerByte());
CharBuffer sandbox = CharBuffer.allocate(cbufsiz);
// First try ISO-2022-JP, since there is no ambiguity
--- /u/martin/ws/mustang/test/java/lang/StringCoding/Enormous.java 1969-12-31 16:00:00.000000000 -0800
+++ /u/martin/ws/nio/test/java/lang/StringCoding/Enormous.java 2004-09-14 22:21:26.017575000 -0700
@@ -0,0 +1,11 @@
+/* @test @(#)Enormous.java 1.1 04/09/14
+ * @bug 4949631
+ * @summary Check for ability to recode arrays of odd sizes > 16MB
+ */
+
+public class Enormous {
+ public static void main(String[] args) throws Exception {
+ new String(new char[16777217]).getBytes("ASCII");
+ new String(new byte[16777217],"ASCII");
+ }
+}
###@###.### 2004-11-09 00:34:44 GMT
|
EVALUATION
True. -- ###@###.### 2003/11/15
Here's a more concise test case:
----------------------------------------------------------
class Bug {
static void test(int size) {
try {new String(new char[size]).getBytes();}
catch (Throwable t) {
System.out.println("Failed with size="+size);
t.printStackTrace();
}}
public static void main(String[] args) throws Exception {
for (int i = 0; i < 10; i++)
test(16777216+i);
}
}
----------------------------------------------------------
which fails in the same manner.
###@###.### 2004-09-02
Ah yes, 16MB is 24 bits, which is the range of accuracy of a float,
and floats are used for maxBytesPerChar and friends.
We need to be more careful with losing bits near
Integer.MAX_VALUE.
###@###.### 2004-09-05
Analysis reveals that both encoders and decoders have the same bug.
See this program:
class Bug4 {
public static void main(String[] args) throws Exception {
try {new String(new char[16777217]).getBytes("ASCII");}
catch (Throwable t) {t.printStackTrace();}
try {new String(new byte[16777217],"ASCII");}
catch (Throwable t) {t.printStackTrace();}
}
}
###@###.### 2004-09-05
|