-
Bug
-
Resolution: Fixed
-
P4
-
7
-
x86
-
windows_xp
FULL PRODUCT VERSION :
java version "1.7.0-ea"
Java(TM) SE Runtime Environment (build 1.7.0-ea-b43)
Java HotSpot(TM) Client VM (build 14.0-b10, mixed mode, sharing)
ADDITIONAL OS VERSION INFORMATION :
Windows XP SR-2
A DESCRIPTION OF THE PROBLEM :
UTF_8$Decoder returns wrong results, see results ...
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
run source
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
new byte[]{(byte)0xC0} ---> CoderResult.malformedForLength(1)
new byte[]{(byte)0xE1, (byte)0x40 ---> CoderResult.malformedForLength(1)
new byte[]{(byte)0xE1, (byte)0x80, (byte)0x42} ---> CoderResult.malformedForLength(1)
ACTUAL -
new byte[]{(byte)0xC0} ---> CoderResult..UNDERFLOW
new byte[]{(byte)0xE1, (byte)0x40 ---> CoderResult.UNDERFLOW
new byte[]{(byte)0xE1, (byte)0x80, (byte)0x42} ---> CoderResult.malformedForLength(2)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package java.nio.charset;
import java.lang.reflect.*;
import java.nio.*;
/**
*
* @author Ulf Zibis <Ulf.Zibis at CoSoCo.de>
*/
public class TestCharsetDecoder extends CharsetDecoder {
public CharsetDecoder decoder;
public Class<CharsetDecoder> decoderClass;
public Method decodeArrayLoopMethod;
public Method decodeBufferLoopMethod;
public TestCharsetDecoder(CharsetDecoder decoder) throws Exception {
super(decoder.charset(), decoder.averageCharsPerByte(), decoder.maxCharsPerByte());
this.decoder = decoder;
decoderClass = (Class<CharsetDecoder>)Class.forName(decoder.charset().getClass().getName()+"$Decoder");
decodeArrayLoopMethod = decoderClass.getDeclaredMethod(
"decodeArrayLoop", ByteBuffer.class, CharBuffer.class);
decodeArrayLoopMethod.setAccessible(true);
decodeBufferLoopMethod = decoderClass.getDeclaredMethod(
"decodeBufferLoop", ByteBuffer.class, CharBuffer.class);
decodeBufferLoopMethod.setAccessible(true);
}
public CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
return decoder.decodeLoop(in, out);
}
public CoderResult decodeArrayLoop(ByteBuffer in, CharBuffer out) throws Exception {
return (CoderResult)decodeArrayLoopMethod.invoke(decoder, in, out);
}
public CoderResult decodeBufferLoop(ByteBuffer in, CharBuffer out) throws Exception {
return (CoderResult)decodeBufferLoopMethod.invoke(decoder, in, out);
}
}
package sun.nio.cs;
import java.io.*;
import java.nio.*;
import java.nio.charset.*;
import java.util.*;
import org.junit.*;
import static org.junit.Assert.*;
import static org.junit.Assume.*;
import org.junit.runner.*;
import org.junit.runners.*;
import org.junit.runners.Parameterized.*;
/**
*
* @author Ulf.Zibis @ CoSoCo.de
*/
@RunWith(Parameterized.class)
public class UTF_8Test {
// test parameters:
private static final CoderResult MAL_1 = CoderResult.malformedForLength(1);
private static final CoderResult MAL_2 = CoderResult.malformedForLength(2);
private static final CoderResult MAL_3 = CoderResult.malformedForLength(3);
private static final CoderResult UFLOW = CoderResult.UNDERFLOW;
private static final Object[][] PARAMETERS = new Object[][]{
// samples:
/* 0 */ { new byte[]{(byte)0xC0, (byte)0x40}, 0, MAL_1 }, // !UTF, 'A'
/* 1 */ { new byte[]{(byte)0xC1, (byte)0x41}, 0, MAL_1 }, // !UTF, 'B'
/* 2 */ { new byte[]{(byte)0xC2, (byte)0x42}, 0, MAL_2 }, // UTF_21, 'C'
/* 3 */ { new byte[]{(byte)0xC3, (byte)0xA0}, 2, UFLOW }, // UTF_21, UTF_22
/* 4 */ { new byte[]{(byte)0xC0}, 0, MAL_1 }, // !UTF
/* 5 */ { new byte[]{(byte)0xC1}, 0, MAL_1 }, // !UTF
/* 6 */ { new byte[]{(byte)0xC2}, 0, UFLOW }, // UTF_21
/* 7 */ { new byte[]{(byte)0xE0, (byte)0x80, (byte)0x80}, 0, MAL_2 }, // UTF_31, !UTF_32, UTF_33
/* 8 */ { new byte[]{(byte)0xE1, (byte)0x80, (byte)0x42}, 0, MAL_3 }, // UTF_31, UTF_32, 'C'
/* 9 */ { new byte[]{(byte)0xE0, (byte)0xA0, (byte)0x80}, 3, UFLOW }, // UTF_31, UTF_32, UTF_33
/* 10 */ { new byte[]{(byte)0xE1, (byte)0x80, (byte)0x81}, 3, UFLOW }, // UTF_31, UTF_32, UTF_33
/* 11 */ { new byte[]{(byte)0xE1, (byte)0x40}, 0, MAL_2 }, // UTF_31, 'A'
/* 12 */ { new byte[]{(byte)0xE0, (byte)0xA0}, 0, UFLOW }, // UTF_31, UTF_32
/* 13 */ { new byte[]{(byte)0xE1}, 0, UFLOW }, // UTF_31
/* 14 */ { new byte[]{(byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80}, 0, MAL_1 }, // 5 * !UTF
/* 15 */ { new byte[]{(byte)0xC0, (byte)0xC0, (byte)0xC0, (byte)0xC0, (byte)0xC0}, 0, MAL_1 }, // 5 * !UTF
/* 16 */ { new byte[]{(byte)0xC0, (byte)0xC0, (byte)0x42}, 0, MAL_1 }, // !UTF, !UTF, 'C'
// /* 0 */ { new char[] {'\u0041', '\u0042', '\uFFFE'} },
// /* 1 */ { new char[] {'\u0041', '\u0042', '\uFFFF'} },
};
private static final int PROCESS_SINGLE = -1;
private static int parametersInTest = 0;
// parameters:
private static Charset cs;
private static ByteBuffer inBytes;
private static int expectedPos;
private static CoderResult expected;
// private static CharBuffer inChars;
// temp:
private TestCharsetDecoder decoder;
// private CharsetEncoder encoder;
boolean ok = false;
// results:
private CharBuffer outChars;
// private ByteBuffer outBytes;
public UTF_8Test(byte[] inBytes, int position, CoderResult result) throws IOException {
byte[] previous = null;
if (this.inBytes != null)
previous = this.inBytes.array();
cs = Charset.forName("UTF-8");
this.inBytes = ByteBuffer.wrap(inBytes);
// this.inChars = CharBuffer.wrap(inChars);
expectedPos = position;
expected = result;
if (previous != inBytes) {
// System.out.println("\n>>> PARAMETERS["+(parametersInTest++)+"]: "+Arrays.toString(inBytes));
System.out.print("\n>>> PARAMETERS["+(parametersInTest++)+"]: [");
for (int i=0; i<inBytes.length; i++)
System.out.print(Integer.toBinaryString(inBytes[i]&0xFF)+(i<inBytes.length-1 ? ", " :""));
System.out.println("]");
// System.out.printf(" [%h, %h]%n", new Integer(3), new Integer(-3));
// System.out.printf(" [%X, %X, %X, %X, %X]%n", inBytes);
// System.out.printf(" [%X, %X, %X, %X, %X]%n", inBytes[0], inBytes[1]);
}
}
@Parameters
public static Collection data() {
List parameters = new ArrayList(Arrays.asList(PROCESS_SINGLE < 0 ?
PARAMETERS : new Object[]{PARAMETERS[PROCESS_SINGLE]}));
return parameters;
}
@Before
public void setUp() throws Exception {
decoder = new TestCharsetDecoder(cs.newDecoder());
outChars = CharBuffer.allocate((int)(inBytes.capacity()*decoder.maxCharsPerByte()));
inBytes.rewind();
// assumeTrue(cs.canEncode());
// encoder = cs.newEncoder();
// outBytes = ByteBuffer.allocate((int)(inChars.capacity()*encoder.maxBytesPerChar()));
}
@After
public void tearDown() throws Exception {
System.out.println(ok ? " > OK" : "");
}
@Ignore
@Test
public void testDecodeArrayLoop() throws Exception {
System.out.print("NOW TEST > ["+decoder.decoderClass.getName()+"] decodeArrayLoop");
CoderResult result = null;
result = decoder.decodeArrayLoop(inBytes, outChars);
int position = inBytes.position();
assertEquals("position", expectedPos, position);
assertEquals("decodeArrayLoop()", expected, result);
if (result.isOverflow())
result.throwException();
ok = true;
}
@Ignore
@Test
public void testDecodeBufferLoop() throws Exception {
System.out.print("NOW TEST > ["+decoder.decoderClass.getName()+"] decodeBufferLoop");
CoderResult result = null;
result = decoder.decodeBufferLoop(inBytes, outChars);
int position = inBytes.position();
assertEquals("position", expectedPos, position);
assertEquals("decodeBufferLoop()", expected, result);
if (result.isOverflow())
result.throwException();
ok = true;
}
@Ignore
@Test
public void testDecodeLoop() throws CharacterCodingException {
System.out.print("NOW TEST > ["+decoder.decoderClass.getName()+"] decodeLoop");
CoderResult result = null;
result = decoder.decodeLoop(inBytes, outChars);
int position = inBytes.position();
assertEquals("position", expectedPos, position);
assertEquals("decodeLoop()", expected, result);
if (result.isOverflow())
result.throwException();
ok = true;
}
@Test
public void testDecoder() throws CharacterCodingException {
System.out.print("NOW TEST > ["+decoder.decoderClass.getName()+"] decode");
CoderResult result = null;
result = decoder.decode(inBytes, outChars, false);
int position = inBytes.position();
assertEquals("position", expectedPos, position);
// assertEquals("decode()", expected, result); // for pessimistic estimation
if (expected.isMalformed())
assertEquals("decode()", MAL_1, result);
else
assertEquals("decode()", expected, result);
if (result.isOverflow())
result.throwException();
// inBytes.rewind();
// outChars.clear();
result = decoder.decode(inBytes, outChars, true);
position = inBytes.position();
assertEquals("position", expectedPos, position);
if (expected.isUnderflow() && inBytes.hasRemaining())
assertEquals("decode()", CoderResult.malformedForLength(inBytes.remaining()), result);
else if (expected.isMalformed())
assertEquals("decode()", MAL_1, result);
else
assertEquals("decode()", expected, result);
if (result.isOverflow())
result.throwException();
ok = true;
}
}
---------- END SOURCE ----------
java version "1.7.0-ea"
Java(TM) SE Runtime Environment (build 1.7.0-ea-b43)
Java HotSpot(TM) Client VM (build 14.0-b10, mixed mode, sharing)
ADDITIONAL OS VERSION INFORMATION :
Windows XP SR-2
A DESCRIPTION OF THE PROBLEM :
UTF_8$Decoder returns wrong results, see results ...
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
run source
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
new byte[]{(byte)0xC0} ---> CoderResult.malformedForLength(1)
new byte[]{(byte)0xE1, (byte)0x40 ---> CoderResult.malformedForLength(1)
new byte[]{(byte)0xE1, (byte)0x80, (byte)0x42} ---> CoderResult.malformedForLength(1)
ACTUAL -
new byte[]{(byte)0xC0} ---> CoderResult..UNDERFLOW
new byte[]{(byte)0xE1, (byte)0x40 ---> CoderResult.UNDERFLOW
new byte[]{(byte)0xE1, (byte)0x80, (byte)0x42} ---> CoderResult.malformedForLength(2)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package java.nio.charset;
import java.lang.reflect.*;
import java.nio.*;
/**
*
* @author Ulf Zibis <Ulf.Zibis at CoSoCo.de>
*/
public class TestCharsetDecoder extends CharsetDecoder {
public CharsetDecoder decoder;
public Class<CharsetDecoder> decoderClass;
public Method decodeArrayLoopMethod;
public Method decodeBufferLoopMethod;
public TestCharsetDecoder(CharsetDecoder decoder) throws Exception {
super(decoder.charset(), decoder.averageCharsPerByte(), decoder.maxCharsPerByte());
this.decoder = decoder;
decoderClass = (Class<CharsetDecoder>)Class.forName(decoder.charset().getClass().getName()+"$Decoder");
decodeArrayLoopMethod = decoderClass.getDeclaredMethod(
"decodeArrayLoop", ByteBuffer.class, CharBuffer.class);
decodeArrayLoopMethod.setAccessible(true);
decodeBufferLoopMethod = decoderClass.getDeclaredMethod(
"decodeBufferLoop", ByteBuffer.class, CharBuffer.class);
decodeBufferLoopMethod.setAccessible(true);
}
public CoderResult decodeLoop(ByteBuffer in, CharBuffer out) {
return decoder.decodeLoop(in, out);
}
public CoderResult decodeArrayLoop(ByteBuffer in, CharBuffer out) throws Exception {
return (CoderResult)decodeArrayLoopMethod.invoke(decoder, in, out);
}
public CoderResult decodeBufferLoop(ByteBuffer in, CharBuffer out) throws Exception {
return (CoderResult)decodeBufferLoopMethod.invoke(decoder, in, out);
}
}
package sun.nio.cs;
import java.io.*;
import java.nio.*;
import java.nio.charset.*;
import java.util.*;
import org.junit.*;
import static org.junit.Assert.*;
import static org.junit.Assume.*;
import org.junit.runner.*;
import org.junit.runners.*;
import org.junit.runners.Parameterized.*;
/**
*
* @author Ulf.Zibis @ CoSoCo.de
*/
@RunWith(Parameterized.class)
public class UTF_8Test {
// test parameters:
private static final CoderResult MAL_1 = CoderResult.malformedForLength(1);
private static final CoderResult MAL_2 = CoderResult.malformedForLength(2);
private static final CoderResult MAL_3 = CoderResult.malformedForLength(3);
private static final CoderResult UFLOW = CoderResult.UNDERFLOW;
private static final Object[][] PARAMETERS = new Object[][]{
// samples:
/* 0 */ { new byte[]{(byte)0xC0, (byte)0x40}, 0, MAL_1 }, // !UTF, 'A'
/* 1 */ { new byte[]{(byte)0xC1, (byte)0x41}, 0, MAL_1 }, // !UTF, 'B'
/* 2 */ { new byte[]{(byte)0xC2, (byte)0x42}, 0, MAL_2 }, // UTF_21, 'C'
/* 3 */ { new byte[]{(byte)0xC3, (byte)0xA0}, 2, UFLOW }, // UTF_21, UTF_22
/* 4 */ { new byte[]{(byte)0xC0}, 0, MAL_1 }, // !UTF
/* 5 */ { new byte[]{(byte)0xC1}, 0, MAL_1 }, // !UTF
/* 6 */ { new byte[]{(byte)0xC2}, 0, UFLOW }, // UTF_21
/* 7 */ { new byte[]{(byte)0xE0, (byte)0x80, (byte)0x80}, 0, MAL_2 }, // UTF_31, !UTF_32, UTF_33
/* 8 */ { new byte[]{(byte)0xE1, (byte)0x80, (byte)0x42}, 0, MAL_3 }, // UTF_31, UTF_32, 'C'
/* 9 */ { new byte[]{(byte)0xE0, (byte)0xA0, (byte)0x80}, 3, UFLOW }, // UTF_31, UTF_32, UTF_33
/* 10 */ { new byte[]{(byte)0xE1, (byte)0x80, (byte)0x81}, 3, UFLOW }, // UTF_31, UTF_32, UTF_33
/* 11 */ { new byte[]{(byte)0xE1, (byte)0x40}, 0, MAL_2 }, // UTF_31, 'A'
/* 12 */ { new byte[]{(byte)0xE0, (byte)0xA0}, 0, UFLOW }, // UTF_31, UTF_32
/* 13 */ { new byte[]{(byte)0xE1}, 0, UFLOW }, // UTF_31
/* 14 */ { new byte[]{(byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80}, 0, MAL_1 }, // 5 * !UTF
/* 15 */ { new byte[]{(byte)0xC0, (byte)0xC0, (byte)0xC0, (byte)0xC0, (byte)0xC0}, 0, MAL_1 }, // 5 * !UTF
/* 16 */ { new byte[]{(byte)0xC0, (byte)0xC0, (byte)0x42}, 0, MAL_1 }, // !UTF, !UTF, 'C'
// /* 0 */ { new char[] {'\u0041', '\u0042', '\uFFFE'} },
// /* 1 */ { new char[] {'\u0041', '\u0042', '\uFFFF'} },
};
private static final int PROCESS_SINGLE = -1;
private static int parametersInTest = 0;
// parameters:
private static Charset cs;
private static ByteBuffer inBytes;
private static int expectedPos;
private static CoderResult expected;
// private static CharBuffer inChars;
// temp:
private TestCharsetDecoder decoder;
// private CharsetEncoder encoder;
boolean ok = false;
// results:
private CharBuffer outChars;
// private ByteBuffer outBytes;
public UTF_8Test(byte[] inBytes, int position, CoderResult result) throws IOException {
byte[] previous = null;
if (this.inBytes != null)
previous = this.inBytes.array();
cs = Charset.forName("UTF-8");
this.inBytes = ByteBuffer.wrap(inBytes);
// this.inChars = CharBuffer.wrap(inChars);
expectedPos = position;
expected = result;
if (previous != inBytes) {
// System.out.println("\n>>> PARAMETERS["+(parametersInTest++)+"]: "+Arrays.toString(inBytes));
System.out.print("\n>>> PARAMETERS["+(parametersInTest++)+"]: [");
for (int i=0; i<inBytes.length; i++)
System.out.print(Integer.toBinaryString(inBytes[i]&0xFF)+(i<inBytes.length-1 ? ", " :""));
System.out.println("]");
// System.out.printf(" [%h, %h]%n", new Integer(3), new Integer(-3));
// System.out.printf(" [%X, %X, %X, %X, %X]%n", inBytes);
// System.out.printf(" [%X, %X, %X, %X, %X]%n", inBytes[0], inBytes[1]);
}
}
@Parameters
public static Collection data() {
List parameters = new ArrayList(Arrays.asList(PROCESS_SINGLE < 0 ?
PARAMETERS : new Object[]{PARAMETERS[PROCESS_SINGLE]}));
return parameters;
}
@Before
public void setUp() throws Exception {
decoder = new TestCharsetDecoder(cs.newDecoder());
outChars = CharBuffer.allocate((int)(inBytes.capacity()*decoder.maxCharsPerByte()));
inBytes.rewind();
// assumeTrue(cs.canEncode());
// encoder = cs.newEncoder();
// outBytes = ByteBuffer.allocate((int)(inChars.capacity()*encoder.maxBytesPerChar()));
}
@After
public void tearDown() throws Exception {
System.out.println(ok ? " > OK" : "");
}
@Ignore
@Test
public void testDecodeArrayLoop() throws Exception {
System.out.print("NOW TEST > ["+decoder.decoderClass.getName()+"] decodeArrayLoop");
CoderResult result = null;
result = decoder.decodeArrayLoop(inBytes, outChars);
int position = inBytes.position();
assertEquals("position", expectedPos, position);
assertEquals("decodeArrayLoop()", expected, result);
if (result.isOverflow())
result.throwException();
ok = true;
}
@Ignore
@Test
public void testDecodeBufferLoop() throws Exception {
System.out.print("NOW TEST > ["+decoder.decoderClass.getName()+"] decodeBufferLoop");
CoderResult result = null;
result = decoder.decodeBufferLoop(inBytes, outChars);
int position = inBytes.position();
assertEquals("position", expectedPos, position);
assertEquals("decodeBufferLoop()", expected, result);
if (result.isOverflow())
result.throwException();
ok = true;
}
@Ignore
@Test
public void testDecodeLoop() throws CharacterCodingException {
System.out.print("NOW TEST > ["+decoder.decoderClass.getName()+"] decodeLoop");
CoderResult result = null;
result = decoder.decodeLoop(inBytes, outChars);
int position = inBytes.position();
assertEquals("position", expectedPos, position);
assertEquals("decodeLoop()", expected, result);
if (result.isOverflow())
result.throwException();
ok = true;
}
@Test
public void testDecoder() throws CharacterCodingException {
System.out.print("NOW TEST > ["+decoder.decoderClass.getName()+"] decode");
CoderResult result = null;
result = decoder.decode(inBytes, outChars, false);
int position = inBytes.position();
assertEquals("position", expectedPos, position);
// assertEquals("decode()", expected, result); // for pessimistic estimation
if (expected.isMalformed())
assertEquals("decode()", MAL_1, result);
else
assertEquals("decode()", expected, result);
if (result.isOverflow())
result.throwException();
// inBytes.rewind();
// outChars.clear();
result = decoder.decode(inBytes, outChars, true);
position = inBytes.position();
assertEquals("position", expectedPos, position);
if (expected.isUnderflow() && inBytes.hasRemaining())
assertEquals("decode()", CoderResult.malformedForLength(inBytes.remaining()), result);
else if (expected.isMalformed())
assertEquals("decode()", MAL_1, result);
else
assertEquals("decode()", expected, result);
if (result.isOverflow())
result.throwException();
ok = true;
}
}
---------- END SOURCE ----------