Home | History | Annotate | Download | only in charset
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package libcore.java.nio.charset;
     18 
     19 import java.nio.ByteBuffer;
     20 import java.nio.CharBuffer;
     21 import java.nio.charset.Charset;
     22 import java.nio.charset.CharsetDecoder;
     23 import java.nio.charset.CharsetEncoder;
     24 import junit.framework.TestCase;
     25 
     26 
     27 /* See bug http://b/1844104.
     28  * Checks for ICU encoder/decoder buffer corruption.
     29  */
     30 public class OldCharsetEncoderDecoderBufferTest extends TestCase {
     31 
     32     /* Checks for a buffer corruption that happens in ICU
     33      * (CharsetDecoderICU) when a decode operation
     34      * is done first with an out-buffer with hasArray()==true, and next with an out-buffer with
     35      * hasArray()==false. In that situation ICU may overwrite the first out-buffer.
     36      */
     37     public void testDecoderOutputBuffer() {
     38         CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
     39 
     40         char[] cBuf = new char[10];
     41         CharBuffer out = CharBuffer.wrap(cBuf);
     42         assertTrue(out.hasArray());
     43         decoder.decode(ByteBuffer.wrap(new byte[]{(byte)'a', (byte)'b', (byte)'c', (byte)'d'}),
     44                        out, false);
     45 
     46         assertEquals("abcd", new String(cBuf, 0, 4));
     47         assertEquals(0, cBuf[4]);
     48         assertEquals(0, cBuf[5]);
     49 
     50         byte[] bBuf = new byte[10];
     51         out = ByteBuffer.wrap(bBuf).asCharBuffer();
     52         assertFalse(out.hasArray());
     53         decoder.decode(ByteBuffer.wrap(new byte[]{(byte)'x'}), out, true);
     54 
     55         assertEquals('x', bBuf[1]);
     56         assertEquals(0, bBuf[3]);
     57 
     58         // check if the first buffer was corrupted by the second decode
     59         assertEquals("abcd", new String(cBuf, 0, 4));
     60         assertEquals(0, cBuf[4]);
     61         assertEquals(0, cBuf[5]);
     62     }
     63 
     64     /* Checks for a buffer corruption that happens in ICU
     65      * (CharsetDecoderICU) when a decode operation
     66      * is done first with an in-buffer with hasArray()==true, and next with an in-buffer with
     67      * hasArray()==false. In that situation ICU may overwrite the array of the first in-buffer.
     68      */
     69     public void testDecoderInputBuffer() {
     70         CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();
     71         CharBuffer out = CharBuffer.wrap(new char[10]);
     72 
     73         byte[] inArray = {(byte)'a', (byte)'b'};
     74         ByteBuffer inWithArray = ByteBuffer.wrap(inArray);
     75         assertTrue(inWithArray.hasArray());
     76         decoder.decode(inWithArray, out, false);
     77         assertEquals('a', inArray[0]);
     78         assertEquals('b', inArray[1]);
     79 
     80         // A read-only ByteBuffer must not expose its array.
     81         ByteBuffer inWithoutArray = ByteBuffer.wrap(new byte[] { (byte) 'x' }).asReadOnlyBuffer();
     82         assertFalse(inWithoutArray.hasArray());
     83         decoder.decode(inWithoutArray, out, true);
     84 
     85         // check whether the first buffer was corrupted by the second decode
     86         assertEquals('a', inArray[0]);
     87         assertEquals('b', inArray[1]);
     88     }
     89 
     90     /* Checks for a buffer corruption that happens in ICU
     91      * (CharsetEncoderICU) when an encode operation
     92      * is done first with an out-buffer with hasArray()==true, and next with an out-buffer with
     93      * hasArray()==false. In that situation ICU may overwrite the first out-buffer.
     94      */
     95     public void testEncoderOutputBuffer() {
     96         CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder();
     97 
     98         byte[] buffer = new byte[10];
     99         ByteBuffer out = ByteBuffer.wrap(buffer);
    100 
    101         assertTrue(out.hasArray());
    102         encoder.encode(CharBuffer.wrap("ab"), out, false);
    103 
    104         assertEquals('a', buffer[0]);
    105         assertEquals('b', buffer[1]);
    106         assertEquals(0, buffer[2]);
    107 
    108         out = ByteBuffer.allocateDirect(10);
    109         // It's no longer possible to get a byte buffer without a backing byte[] on Android.
    110         // This test is useless on Android, unless that changes again. (You can't even
    111         // subclass ByteBuffer because -- although it's non-final -- both the RI and Android
    112         // have [different] package-private abstract methods you'd need to implement but can't.)
    113         //assertFalse(out.hasArray());
    114         encoder.encode(CharBuffer.wrap("x"), out, true);
    115 
    116         // check whether the second decode corrupted the first buffer
    117         assertEquals('a', buffer[0]);
    118         assertEquals('b', buffer[1]);
    119         assertEquals(0, buffer[2]);
    120     }
    121 
    122     /* Checks for a buffer corruption that happens in ICU
    123      * (CharsetEncoderICU) when an encode operation
    124      * is done first with an in-buffer with hasArray()==true, and next with an in-buffer with
    125      * hasArray()==false. In that situation ICU may overwrite the array of the first in-buffer.
    126      */
    127     public void testEncoderInputBuffer() {
    128         CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder();
    129         ByteBuffer out = ByteBuffer.wrap(new byte[10]);
    130 
    131         char[] inArray = {'a', 'b'};
    132         CharBuffer inWithArray = CharBuffer.wrap(inArray);
    133         assertTrue(inWithArray.hasArray());
    134         encoder.encode(inWithArray, out, false);
    135 
    136         assertEquals('a', inArray[0]);
    137         assertEquals('b', inArray[1]);
    138 
    139         CharBuffer inWithoutArray = CharBuffer.wrap("x");
    140         assertFalse(inWithoutArray.hasArray());
    141         encoder.encode(inWithoutArray, out, true);
    142 
    143         // check whether the second decode corrupted the first buffer
    144         assertEquals('a', inArray[0]);
    145         assertEquals('b', inArray[1]);
    146     }
    147 }
    148