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 */ testDecoderOutputBuffer()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 */ testDecoderInputBuffer()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 */ testEncoderOutputBuffer()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 */ testEncoderInputBuffer()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