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

UTF_8$Decoder returns wrong results

    XMLWordPrintable

Details

    • Bug
    • Status: Resolved
    • P4
    • Resolution: Fixed
    • 7
    • 8
    • core-libs

    Description

      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 ----------

      Attachments

        Activity

          People

            sherman Xueming Shen
            ndcosta Nelson Dcosta (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: