1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 package com.google.protobuf;
32 
33 import static org.junit.Assert.assertArrayEquals;
34 import protobuf_unittest.UnittestProto.BoolMessage;
35 import protobuf_unittest.UnittestProto.Int32Message;
36 import protobuf_unittest.UnittestProto.Int64Message;
37 import protobuf_unittest.UnittestProto.TestAllTypes;
38 import protobuf_unittest.UnittestProto.TestRecursiveMessage;
39 import java.io.ByteArrayInputStream;
40 import java.io.ByteArrayOutputStream;
41 import java.io.FilterInputStream;
42 import java.io.IOException;
43 import java.io.InputStream;
44 import java.nio.ByteBuffer;
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.List;
48 import junit.framework.TestCase;
49 
50 /**
51  * Unit test for {@link CodedInputStream}.
52  *
53  * @author kenton@google.com Kenton Varda
54  */
55 public class CodedInputStreamTest extends TestCase {
56 
57   private static final int DEFAULT_BLOCK_SIZE = 4096;
58 
59   private enum InputType {
60     ARRAY {
61       @Override
newDecoder(byte[] data, int blockSize)62       CodedInputStream newDecoder(byte[] data, int blockSize) {
63         return CodedInputStream.newInstance(data);
64       }
65     },
66     NIO_HEAP {
67       @Override
newDecoder(byte[] data, int blockSize)68       CodedInputStream newDecoder(byte[] data, int blockSize) {
69         return CodedInputStream.newInstance(ByteBuffer.wrap(data));
70       }
71     },
72     NIO_DIRECT {
73       @Override
newDecoder(byte[] data, int blockSize)74       CodedInputStream newDecoder(byte[] data, int blockSize) {
75         ByteBuffer buffer = ByteBuffer.allocateDirect(data.length);
76         buffer.put(data);
77         buffer.flip();
78         return CodedInputStream.newInstance(buffer);
79       }
80     },
81     STREAM {
82       @Override
newDecoder(byte[] data, int blockSize)83       CodedInputStream newDecoder(byte[] data, int blockSize) {
84         return CodedInputStream.newInstance(new SmallBlockInputStream(data, blockSize));
85       }
86     },
87     ITER_DIRECT {
88       @Override
newDecoder(byte[] data, int blockSize)89       CodedInputStream newDecoder(byte[] data, int blockSize) {
90         if (blockSize > DEFAULT_BLOCK_SIZE) {
91           blockSize = DEFAULT_BLOCK_SIZE;
92         }
93         ArrayList<ByteBuffer> input = new ArrayList<ByteBuffer>();
94         for (int i = 0; i < data.length; i += blockSize) {
95           int rl = Math.min(blockSize, data.length - i);
96           ByteBuffer rb = ByteBuffer.allocateDirect(rl);
97           rb.put(data, i, rl);
98           rb.flip();
99           input.add(rb);
100         }
101         return CodedInputStream.newInstance(input);
102       }
103     },
104     STREAM_ITER_DIRECT {
105       @Override
newDecoder(byte[] data, int blockSize)106       CodedInputStream newDecoder(byte[] data, int blockSize) {
107         if (blockSize > DEFAULT_BLOCK_SIZE) {
108           blockSize = DEFAULT_BLOCK_SIZE;
109         }
110         ArrayList<ByteBuffer> input = new ArrayList<ByteBuffer>();
111         for (int i = 0; i < data.length; i += blockSize) {
112           int rl = Math.min(blockSize, data.length - i);
113           ByteBuffer rb = ByteBuffer.allocateDirect(rl);
114           rb.put(data, i, rl);
115           rb.flip();
116           input.add(rb);
117         }
118         return CodedInputStream.newInstance(new IterableByteBufferInputStream(input));
119       }
120     };
121 
newDecoder(byte[] data)122     CodedInputStream newDecoder(byte[] data) {
123       return newDecoder(data, data.length);
124     }
125 
newDecoder(byte[] data, int blockSize)126     abstract CodedInputStream newDecoder(byte[] data, int blockSize);
127   }
128 
129   /**
130    * Helper to construct a byte array from a bunch of bytes. The inputs are actually ints so that I
131    * can use hex notation and not get stupid errors about precision.
132    */
bytes(int... bytesAsInts)133   private byte[] bytes(int... bytesAsInts) {
134     byte[] bytes = new byte[bytesAsInts.length];
135     for (int i = 0; i < bytesAsInts.length; i++) {
136       bytes[i] = (byte) bytesAsInts[i];
137     }
138     return bytes;
139   }
140 
141   /**
142    * An InputStream which limits the number of bytes it reads at a time. We use this to make sure
143    * that CodedInputStream doesn't screw up when reading in small blocks.
144    */
145   private static final class SmallBlockInputStream extends FilterInputStream {
146     private final int blockSize;
147     private int skipCalls;
148     private int readCalls;
149 
SmallBlockInputStream(byte[] data, int blockSize)150     public SmallBlockInputStream(byte[] data, int blockSize) {
151       super(new ByteArrayInputStream(data));
152       this.blockSize = blockSize;
153     }
154 
155     @Override
read()156     public int read() throws IOException {
157       readCalls++;
158       return super.read();
159     }
160 
161     @Override
read(byte[] b)162     public int read(byte[] b) throws IOException {
163       readCalls++;
164       return super.read(b, 0, Math.min(b.length, blockSize));
165     }
166 
167     @Override
read(byte[] b, int off, int len)168     public int read(byte[] b, int off, int len) throws IOException {
169       readCalls++;
170       return super.read(b, off, Math.min(len, blockSize));
171     }
172 
173     @Override
skip(long len)174     public long skip(long len) throws IOException {
175       skipCalls++;
176       return super.skip(Math.min(len, blockSize));
177     }
178   }
179 
assertDataConsumed(String msg, byte[] data, CodedInputStream input)180   private void assertDataConsumed(String msg, byte[] data, CodedInputStream input)
181       throws IOException {
182     assertEquals(msg, data.length, input.getTotalBytesRead());
183     assertTrue(msg, input.isAtEnd());
184   }
185 
186   /**
187    * Parses the given bytes using readRawVarint32() and readRawVarint64() and checks that the result
188    * matches the given value.
189    */
assertReadVarint(byte[] data, long value)190   private void assertReadVarint(byte[] data, long value) throws Exception {
191     for (InputType inputType : InputType.values()) {
192       // Try different block sizes.
193       for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
194         CodedInputStream input = inputType.newDecoder(data, blockSize);
195         assertEquals(inputType.name(), (int) value, input.readRawVarint32());
196         assertDataConsumed(inputType.name(), data, input);
197 
198         input = inputType.newDecoder(data, blockSize);
199         assertEquals(inputType.name(), value, input.readRawVarint64());
200         assertDataConsumed(inputType.name(), data, input);
201 
202         input = inputType.newDecoder(data, blockSize);
203         assertEquals(inputType.name(), value, input.readRawVarint64SlowPath());
204         assertDataConsumed(inputType.name(), data, input);
205 
206         input = inputType.newDecoder(data, blockSize);
207         assertTrue(inputType.name(), input.skipField(WireFormat.WIRETYPE_VARINT));
208         assertDataConsumed(inputType.name(), data, input);
209       }
210     }
211 
212     // Try reading direct from an InputStream.  We want to verify that it
213     // doesn't read past the end of the input, so we copy to a new, bigger
214     // array first.
215     byte[] longerData = new byte[data.length + 1];
216     System.arraycopy(data, 0, longerData, 0, data.length);
217     InputStream rawInput = new ByteArrayInputStream(longerData);
218     assertEquals((int) value, CodedInputStream.readRawVarint32(rawInput));
219     assertEquals(1, rawInput.available());
220   }
221 
222   /**
223    * Parses the given bytes using readRawVarint32() and readRawVarint64() and expects them to fail
224    * with an InvalidProtocolBufferException whose description matches the given one.
225    */
assertReadVarintFailure(InvalidProtocolBufferException expected, byte[] data)226   private void assertReadVarintFailure(InvalidProtocolBufferException expected, byte[] data)
227       throws Exception {
228     for (InputType inputType : InputType.values()) {
229       try {
230         CodedInputStream input = inputType.newDecoder(data);
231         input.readRawVarint32();
232         fail(inputType.name() + ": Should have thrown an exception.");
233       } catch (InvalidProtocolBufferException e) {
234         assertEquals(inputType.name(), expected.getMessage(), e.getMessage());
235       }
236       try {
237         CodedInputStream input = inputType.newDecoder(data);
238         input.readRawVarint64();
239         fail(inputType.name() + ": Should have thrown an exception.");
240       } catch (InvalidProtocolBufferException e) {
241         assertEquals(inputType.name(), expected.getMessage(), e.getMessage());
242       }
243     }
244 
245     // Make sure we get the same error when reading direct from an InputStream.
246     try {
247       CodedInputStream.readRawVarint32(new ByteArrayInputStream(data));
248       fail("Should have thrown an exception.");
249     } catch (InvalidProtocolBufferException e) {
250       assertEquals(expected.getMessage(), e.getMessage());
251     }
252   }
253 
254   /** Tests readRawVarint32() and readRawVarint64(). */
testReadVarint()255   public void testReadVarint() throws Exception {
256     assertReadVarint(bytes(0x00), 0);
257     assertReadVarint(bytes(0x01), 1);
258     assertReadVarint(bytes(0x7f), 127);
259     // 14882
260     assertReadVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7));
261     // 2961488830
262     assertReadVarint(
263         bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
264         (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | (0x0bL << 28));
265 
266     // 64-bit
267     // 7256456126
268     assertReadVarint(
269         bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
270         (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | (0x1bL << 28));
271     // 41256202580718336
272     assertReadVarint(
273         bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
274         (0x00 << 0)
275             | (0x66 << 7)
276             | (0x6b << 14)
277             | (0x1c << 21)
278             | (0x43L << 28)
279             | (0x49L << 35)
280             | (0x24L << 42)
281             | (0x49L << 49));
282     // 11964378330978735131
283     assertReadVarint(
284         bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
285         (0x1b << 0)
286             | (0x28 << 7)
287             | (0x79 << 14)
288             | (0x42 << 21)
289             | (0x3bL << 28)
290             | (0x56L << 35)
291             | (0x00L << 42)
292             | (0x05L << 49)
293             | (0x26L << 56)
294             | (0x01L << 63));
295 
296     // Failures
297     assertReadVarintFailure(
298         InvalidProtocolBufferException.malformedVarint(),
299         bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00));
300     assertReadVarintFailure(InvalidProtocolBufferException.truncatedMessage(), bytes(0x80));
301   }
302 
303   /**
304    * Parses the given bytes using readRawLittleEndian32() and checks that the result matches the
305    * given value.
306    */
assertReadLittleEndian32(byte[] data, int value)307   private void assertReadLittleEndian32(byte[] data, int value) throws Exception {
308     for (InputType inputType : InputType.values()) {
309       // Try different block sizes.
310       for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
311         CodedInputStream input = inputType.newDecoder(data, blockSize);
312         assertEquals(inputType.name(), value, input.readRawLittleEndian32());
313         assertTrue(inputType.name(), input.isAtEnd());
314       }
315     }
316   }
317 
318   /**
319    * Parses the given bytes using readRawLittleEndian64() and checks that the result matches the
320    * given value.
321    */
assertReadLittleEndian64(byte[] data, long value)322   private void assertReadLittleEndian64(byte[] data, long value) throws Exception {
323     for (InputType inputType : InputType.values()) {
324       // Try different block sizes.
325       for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
326         CodedInputStream input = inputType.newDecoder(data, blockSize);
327         assertEquals(inputType.name(), value, input.readRawLittleEndian64());
328         assertTrue(inputType.name(), input.isAtEnd());
329       }
330     }
331   }
332 
333   /** Tests readRawLittleEndian32() and readRawLittleEndian64(). */
testReadLittleEndian()334   public void testReadLittleEndian() throws Exception {
335     assertReadLittleEndian32(bytes(0x78, 0x56, 0x34, 0x12), 0x12345678);
336     assertReadLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
337 
338     assertReadLittleEndian64(
339         bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12), 0x123456789abcdef0L);
340     assertReadLittleEndian64(
341         bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef012345678L);
342   }
343 
344   /** Test decodeZigZag32() and decodeZigZag64(). */
testDecodeZigZag()345   public void testDecodeZigZag() throws Exception {
346     assertEquals(0, CodedInputStream.decodeZigZag32(0));
347     assertEquals(-1, CodedInputStream.decodeZigZag32(1));
348     assertEquals(1, CodedInputStream.decodeZigZag32(2));
349     assertEquals(-2, CodedInputStream.decodeZigZag32(3));
350     assertEquals(0x3FFFFFFF, CodedInputStream.decodeZigZag32(0x7FFFFFFE));
351     assertEquals(0xC0000000, CodedInputStream.decodeZigZag32(0x7FFFFFFF));
352     assertEquals(0x7FFFFFFF, CodedInputStream.decodeZigZag32(0xFFFFFFFE));
353     assertEquals(0x80000000, CodedInputStream.decodeZigZag32(0xFFFFFFFF));
354 
355     assertEquals(0, CodedInputStream.decodeZigZag64(0));
356     assertEquals(-1, CodedInputStream.decodeZigZag64(1));
357     assertEquals(1, CodedInputStream.decodeZigZag64(2));
358     assertEquals(-2, CodedInputStream.decodeZigZag64(3));
359     assertEquals(0x000000003FFFFFFFL, CodedInputStream.decodeZigZag64(0x000000007FFFFFFEL));
360     assertEquals(0xFFFFFFFFC0000000L, CodedInputStream.decodeZigZag64(0x000000007FFFFFFFL));
361     assertEquals(0x000000007FFFFFFFL, CodedInputStream.decodeZigZag64(0x00000000FFFFFFFEL));
362     assertEquals(0xFFFFFFFF80000000L, CodedInputStream.decodeZigZag64(0x00000000FFFFFFFFL));
363     assertEquals(0x7FFFFFFFFFFFFFFFL, CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFEL));
364     assertEquals(0x8000000000000000L, CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFFL));
365   }
366 
367   /** Tests reading and parsing a whole message with every field type. */
testReadWholeMessage()368   public void testReadWholeMessage() throws Exception {
369     TestAllTypes message = TestUtil.getAllSet();
370 
371     byte[] rawBytes = message.toByteArray();
372     assertEquals(rawBytes.length, message.getSerializedSize());
373 
374     for (InputType inputType : InputType.values()) {
375       // Try different block sizes.
376       for (int blockSize = 1; blockSize < 256; blockSize *= 2) {
377         TestAllTypes message2 = TestAllTypes.parseFrom(inputType.newDecoder(rawBytes, blockSize));
378         TestUtil.assertAllFieldsSet(message2);
379       }
380     }
381   }
382 
383   /** Tests skipField(). */
testSkipWholeMessage()384   public void testSkipWholeMessage() throws Exception {
385     TestAllTypes message = TestUtil.getAllSet();
386     byte[] rawBytes = message.toByteArray();
387 
388     InputType[] inputTypes = InputType.values();
389     CodedInputStream[] inputs = new CodedInputStream[inputTypes.length];
390     for (int i = 0; i < inputs.length; ++i) {
391       inputs[i] = inputTypes[i].newDecoder(rawBytes);
392     }
393     UnknownFieldSet.Builder unknownFields = UnknownFieldSet.newBuilder();
394 
395     while (true) {
396       CodedInputStream input1 = inputs[0];
397       int tag = input1.readTag();
398       // Ensure that the rest match.
399       for (int i = 1; i < inputs.length; ++i) {
400         assertEquals(inputTypes[i].name(), tag, inputs[i].readTag());
401       }
402       if (tag == 0) {
403         break;
404       }
405       unknownFields.mergeFieldFrom(tag, input1);
406       // Skip the field for the rest of the inputs.
407       for (int i = 1; i < inputs.length; ++i) {
408         inputs[i].skipField(tag);
409       }
410     }
411   }
412 
413 
414   /**
415    * Test that a bug in skipRawBytes() has been fixed: if the skip skips exactly up to a limit, this
416    * should not break things.
417    */
testSkipRawBytesBug()418   public void testSkipRawBytesBug() throws Exception {
419     byte[] rawBytes = new byte[] {1, 2};
420     for (InputType inputType : InputType.values()) {
421       CodedInputStream input = inputType.newDecoder(rawBytes);
422       int limit = input.pushLimit(1);
423       input.skipRawBytes(1);
424       input.popLimit(limit);
425       assertEquals(inputType.name(), 2, input.readRawByte());
426     }
427   }
428 
429   /**
430    * Test that a bug in skipRawBytes() has been fixed: if the skip skips past the end of a buffer
431    * with a limit that has been set past the end of that buffer, this should not break things.
432    */
testSkipRawBytesPastEndOfBufferWithLimit()433   public void testSkipRawBytesPastEndOfBufferWithLimit() throws Exception {
434     byte[] rawBytes = new byte[] {1, 2, 3, 4, 5};
435     for (InputType inputType : InputType.values()) {
436       CodedInputStream input = inputType.newDecoder(rawBytes);
437       int limit = input.pushLimit(4);
438       // In order to expose the bug we need to read at least one byte to prime the
439       // buffer inside the CodedInputStream.
440       assertEquals(inputType.name(), 1, input.readRawByte());
441       // Skip to the end of the limit.
442       input.skipRawBytes(3);
443       assertTrue(inputType.name(), input.isAtEnd());
444       input.popLimit(limit);
445       assertEquals(inputType.name(), 5, input.readRawByte());
446     }
447   }
448 
449   /**
450    * Test that calling skipRawBytes (when not merging a message) actually skips from the underlying
451    * inputstream, regardless of the buffer size used.
452    */
testSkipRawBytesActuallySkips()453   public void testSkipRawBytesActuallySkips() throws Exception {
454     SmallBlockInputStream bytes = new SmallBlockInputStream(new byte[] {1, 2, 3, 4, 5}, 3);
455     CodedInputStream input = CodedInputStream.newInstance(bytes, 1); // Tiny buffer
456     input.skipRawBytes(3);
457     input.skipRawBytes(2);
458     assertEquals(2, bytes.skipCalls);
459     assertEquals(0, bytes.readCalls);
460   }
461 
testSkipHugeBlob()462   public void testSkipHugeBlob() throws Exception {
463     // Allocate and initialize a 1MB blob.
464     int blobSize = 1 << 20;
465     byte[] blob = new byte[blobSize];
466     for (int i = 0; i < blob.length; i++) {
467       blob[i] = (byte) i;
468     }
469 
470     for (InputType inputType : InputType.values()) {
471       CodedInputStream decoder = inputType.newDecoder(blob);
472       decoder.skipRawBytes(blobSize - 10);
473       byte[] remaining = decoder.readRawBytes(10);
474       assertArrayEquals(Arrays.copyOfRange(blob, blobSize - 10, blobSize), remaining);
475     }
476   }
477 
478   /** Skipping a huge blob should not allocate excessive memory, so there should be no limit */
testSkipMaliciouslyHugeBlob()479   public void testSkipMaliciouslyHugeBlob() throws Exception {
480     InputStream is = new RepeatingInputStream(new byte[]{1}, Integer.MAX_VALUE);
481     CodedInputStream.newInstance(is).skipRawBytes(Integer.MAX_VALUE);
482   }
483 
testReadHugeBlob()484   public void testReadHugeBlob() throws Exception {
485     // Allocate and initialize a 1MB blob.
486     byte[] blob = new byte[1 << 20];
487     for (int i = 0; i < blob.length; i++) {
488       blob[i] = (byte) i;
489     }
490 
491     // Make a message containing it.
492     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
493     TestUtil.setAllFields(builder);
494     builder.setOptionalBytes(ByteString.copyFrom(blob));
495     TestAllTypes message = builder.build();
496 
497     byte[] data = message.toByteArray();
498     for (InputType inputType : InputType.values()) {
499       // Serialize and parse it.  Make sure to parse from an InputStream, not
500       // directly from a ByteString, so that CodedInputStream uses buffered
501       // reading.
502       TestAllTypes message2 = TestAllTypes.parseFrom(inputType.newDecoder(data));
503 
504       assertEquals(inputType.name(), message.getOptionalBytes(), message2.getOptionalBytes());
505 
506       // Make sure all the other fields were parsed correctly.
507       TestAllTypes message3 =
508           TestAllTypes.newBuilder(message2)
509               .setOptionalBytes(TestUtil.getAllSet().getOptionalBytes())
510               .build();
511       TestUtil.assertAllFieldsSet(message3);
512     }
513   }
514 
testReadMaliciouslyLargeBlob()515   public void testReadMaliciouslyLargeBlob() throws Exception {
516     ByteString.Output rawOutput = ByteString.newOutput();
517     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
518 
519     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
520     output.writeRawVarint32(tag);
521     output.writeRawVarint32(0x7FFFFFFF);
522     output.writeRawBytes(new byte[32]); // Pad with a few random bytes.
523     output.flush();
524 
525     byte[] data = rawOutput.toByteString().toByteArray();
526     for (InputType inputType : InputType.values()) {
527       CodedInputStream input = inputType.newDecoder(data);
528       assertEquals(tag, input.readTag());
529       try {
530         input.readBytes();
531         fail(inputType.name() + ": Should have thrown an exception!");
532       } catch (InvalidProtocolBufferException e) {
533         // success.
534       }
535     }
536   }
537 
538   /**
539    * Test we can do messages that are up to CodedInputStream#DEFAULT_SIZE_LIMIT in size (2G or
540    * Integer#MAX_SIZE).
541    *
542    * @throws IOException
543    */
testParseMessagesCloseTo2G()544   public void testParseMessagesCloseTo2G() throws IOException {
545     byte[] serializedMessage = getBigSerializedMessage();
546     // How many of these big messages do we need to take us near our 2G limit?
547     int count = Integer.MAX_VALUE / serializedMessage.length;
548     // Now make an inputstream that will fake a near 2G message of messages
549     // returning our big serialized message 'count' times.
550     InputStream is = new RepeatingInputStream(serializedMessage, count);
551     // Parse should succeed!
552     TestAllTypes.parseFrom(is);
553   }
554 
555   /**
556    * Test there is an exception if a message exceeds CodedInputStream#DEFAULT_SIZE_LIMIT in size (2G
557    * or Integer#MAX_SIZE).
558    *
559    * @throws IOException
560    */
testParseMessagesOver2G()561   public void testParseMessagesOver2G() throws IOException {
562     byte[] serializedMessage = getBigSerializedMessage();
563     // How many of these big messages do we need to take us near our 2G limit?
564     int count = Integer.MAX_VALUE / serializedMessage.length;
565     // Now add one to take us over the limit
566     count++;
567     // Now make an inputstream that will fake a near 2G message of messages
568     // returning our big serialized message 'count' times.
569     InputStream is = new RepeatingInputStream(serializedMessage, count);
570     try {
571       TestAllTypes.parseFrom(is);
572       fail("Should have thrown an exception!");
573     } catch (InvalidProtocolBufferException e) {
574       assertTrue(e.getMessage().contains("too large"));
575     }
576   }
577 
578   /*
579    * @return A serialized big message.
580    */
getBigSerializedMessage()581   private static byte[] getBigSerializedMessage() {
582     byte[] value = new byte[16 * 1024 * 1024];
583     ByteString bsValue = ByteString.wrap(value);
584     return TestAllTypes.newBuilder().setOptionalBytes(bsValue).build().toByteArray();
585   }
586 
587   /*
588    * An input stream that repeats a byte arrays' content a number of times.
589    * Simulates really large input without consuming loads of memory. Used above
590    * to test the parsing behavior when the input size exceeds 2G or close to it.
591    */
592   private static class RepeatingInputStream extends InputStream {
593     private final byte[] serializedMessage;
594     private final int count;
595     private int index = 0;
596     private int offset = 0;
597 
RepeatingInputStream(byte[] serializedMessage, int count)598     RepeatingInputStream(byte[] serializedMessage, int count) {
599       this.serializedMessage = serializedMessage;
600       this.count = count;
601     }
602 
603     @Override
read()604     public int read() throws IOException {
605       if (this.offset == this.serializedMessage.length) {
606         this.index++;
607         this.offset = 0;
608       }
609       if (this.index == this.count) {
610         return -1;
611       }
612       return this.serializedMessage[offset++];
613     }
614   }
615 
makeRecursiveMessage(int depth)616   private TestRecursiveMessage makeRecursiveMessage(int depth) {
617     if (depth == 0) {
618       return TestRecursiveMessage.newBuilder().setI(5).build();
619     } else {
620       return TestRecursiveMessage.newBuilder().setA(makeRecursiveMessage(depth - 1)).build();
621     }
622   }
623 
assertMessageDepth(String msg, TestRecursiveMessage message, int depth)624   private void assertMessageDepth(String msg, TestRecursiveMessage message, int depth) {
625     if (depth == 0) {
626       assertFalse(msg, message.hasA());
627       assertEquals(msg, 5, message.getI());
628     } else {
629       assertTrue(msg, message.hasA());
630       assertMessageDepth(msg, message.getA(), depth - 1);
631     }
632   }
633 
testMaliciousRecursion()634   public void testMaliciousRecursion() throws Exception {
635     byte[] data100 = makeRecursiveMessage(100).toByteArray();
636     byte[] data101 = makeRecursiveMessage(101).toByteArray();
637 
638     for (InputType inputType : InputType.values()) {
639       assertMessageDepth(
640           inputType.name(), TestRecursiveMessage.parseFrom(inputType.newDecoder(data100)), 100);
641 
642       try {
643         TestRecursiveMessage.parseFrom(inputType.newDecoder(data101));
644         fail("Should have thrown an exception!");
645       } catch (InvalidProtocolBufferException e) {
646         // success.
647       }
648 
649       CodedInputStream input = inputType.newDecoder(data100);
650       input.setRecursionLimit(8);
651       try {
652         TestRecursiveMessage.parseFrom(input);
653         fail(inputType.name() + ": Should have thrown an exception!");
654       } catch (InvalidProtocolBufferException e) {
655         // success.
656       }
657     }
658   }
659 
checkSizeLimitExceeded(InvalidProtocolBufferException e)660   private void checkSizeLimitExceeded(InvalidProtocolBufferException e) {
661     assertEquals(InvalidProtocolBufferException.sizeLimitExceeded().getMessage(), e.getMessage());
662   }
663 
testSizeLimit()664   public void testSizeLimit() throws Exception {
665     // NOTE: Size limit only applies to the stream-backed CIS.
666     CodedInputStream input =
667         CodedInputStream.newInstance(
668             new SmallBlockInputStream(TestUtil.getAllSet().toByteArray(), 16));
669     input.setSizeLimit(16);
670 
671     try {
672       TestAllTypes.parseFrom(input);
673       fail("Should have thrown an exception!");
674     } catch (InvalidProtocolBufferException expected) {
675       checkSizeLimitExceeded(expected);
676     }
677   }
678 
testResetSizeCounter()679   public void testResetSizeCounter() throws Exception {
680     // NOTE: Size limit only applies to the stream-backed CIS.
681     CodedInputStream input =
682         CodedInputStream.newInstance(new SmallBlockInputStream(new byte[256], 8));
683     input.setSizeLimit(16);
684     input.readRawBytes(16);
685     assertEquals(16, input.getTotalBytesRead());
686 
687     try {
688       input.readRawByte();
689       fail("Should have thrown an exception!");
690     } catch (InvalidProtocolBufferException expected) {
691       checkSizeLimitExceeded(expected);
692     }
693 
694     input.resetSizeCounter();
695     assertEquals(0, input.getTotalBytesRead());
696     input.readRawByte(); // No exception thrown.
697     input.resetSizeCounter();
698     assertEquals(0, input.getTotalBytesRead());
699     input.readRawBytes(16);
700     assertEquals(16, input.getTotalBytesRead());
701     input.resetSizeCounter();
702 
703     try {
704       input.readRawBytes(17); // Hits limit again.
705       fail("Should have thrown an exception!");
706     } catch (InvalidProtocolBufferException expected) {
707       checkSizeLimitExceeded(expected);
708     }
709   }
710 
testRefillBufferWithCorrectSize()711   public void testRefillBufferWithCorrectSize() throws Exception {
712     // NOTE: refillBuffer only applies to the stream-backed CIS.
713     byte[] bytes = "123456789".getBytes("UTF-8");
714     ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
715     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.length);
716 
717     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
718     output.writeRawVarint32(tag);
719     output.writeRawVarint32(bytes.length);
720     output.writeRawBytes(bytes);
721     output.writeRawVarint32(tag);
722     output.writeRawVarint32(bytes.length);
723     output.writeRawBytes(bytes);
724     output.writeRawByte(4);
725     output.flush();
726 
727     // Input is two string with length 9 and one raw byte.
728     byte[] rawInput = rawOutput.toByteArray();
729     for (int inputStreamBufferLength = 8;
730         inputStreamBufferLength <= rawInput.length + 1;
731         inputStreamBufferLength++) {
732       CodedInputStream input =
733           CodedInputStream.newInstance(new ByteArrayInputStream(rawInput), inputStreamBufferLength);
734       input.setSizeLimit(rawInput.length - 1);
735       input.readString();
736       input.readString();
737       try {
738         input.readRawByte(); // Hits limit.
739         fail("Should have thrown an exception!");
740       } catch (InvalidProtocolBufferException expected) {
741         checkSizeLimitExceeded(expected);
742       }
743     }
744   }
745 
testIsAtEnd()746   public void testIsAtEnd() throws Exception {
747     CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(new byte[5]));
748     try {
749       for (int i = 0; i < 5; i++) {
750         assertEquals(false, input.isAtEnd());
751         input.readRawByte();
752       }
753       assertEquals(true, input.isAtEnd());
754     } catch (Exception e) {
755       throw new AssertionError("Catch exception in the testIsAtEnd", e);
756     }
757   }
758 
testCurrentLimitExceeded()759   public void testCurrentLimitExceeded() throws Exception {
760     byte[] bytes = "123456789".getBytes("UTF-8");
761     ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
762     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.length);
763 
764     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
765     output.writeRawVarint32(tag);
766     output.writeRawVarint32(bytes.length);
767     output.writeRawBytes(bytes);
768     output.flush();
769 
770     byte[] rawInput = rawOutput.toByteArray();
771     CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputStream(rawInput));
772     // The length of the whole rawInput
773     input.setSizeLimit(11);
774     // Some number that is smaller than the rawInput's length
775     // but larger than 2
776     input.pushLimit(5);
777     try {
778       input.readString();
779       fail("Should have thrown an exception");
780     } catch (InvalidProtocolBufferException expected) {
781       assertEquals(
782           expected.getMessage(), InvalidProtocolBufferException.truncatedMessage().getMessage());
783     }
784   }
785 
testSizeLimitMultipleMessages()786   public void testSizeLimitMultipleMessages() throws Exception {
787     // NOTE: Size limit only applies to the stream-backed CIS.
788     byte[] bytes = new byte[256];
789     for (int i = 0; i < bytes.length; i++) {
790       bytes[i] = (byte) i;
791     }
792     CodedInputStream input = CodedInputStream.newInstance(new SmallBlockInputStream(bytes, 7));
793     input.setSizeLimit(16);
794     for (int i = 0; i < 256 / 16; i++) {
795       byte[] message = input.readRawBytes(16);
796       for (int j = 0; j < message.length; j++) {
797         assertEquals(i * 16 + j, message[j] & 0xff);
798       }
799       assertEquals(16, input.getTotalBytesRead());
800       input.resetSizeCounter();
801       assertEquals(0, input.getTotalBytesRead());
802     }
803   }
804 
testReadString()805   public void testReadString() throws Exception {
806     String lorem = "Lorem ipsum dolor sit amet ";
807     StringBuilder builder = new StringBuilder();
808     for (int i = 0; i < 4096; i += lorem.length()) {
809       builder.append(lorem);
810     }
811     lorem = builder.toString().substring(0, 4096);
812     byte[] bytes = lorem.getBytes("UTF-8");
813     ByteString.Output rawOutput = ByteString.newOutput();
814     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.length);
815 
816     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
817     output.writeRawVarint32(tag);
818     output.writeRawVarint32(bytes.length);
819     output.writeRawBytes(bytes);
820     output.flush();
821 
822     byte[] rawInput = rawOutput.toByteString().toByteArray();
823     for (InputType inputType : InputType.values()) {
824       CodedInputStream input = inputType.newDecoder(rawInput);
825       assertEquals(inputType.name(), tag, input.readTag());
826       String text = input.readString();
827       assertEquals(inputType.name(), lorem, text);
828     }
829   }
830 
testReadStringRequireUtf8()831   public void testReadStringRequireUtf8() throws Exception {
832     String lorem = "Lorem ipsum dolor sit amet ";
833     StringBuilder builder = new StringBuilder();
834     for (int i = 0; i < 4096; i += lorem.length()) {
835       builder.append(lorem);
836     }
837     lorem = builder.toString().substring(0, 4096);
838     byte[] bytes = lorem.getBytes("UTF-8");
839     ByteString.Output rawOutput = ByteString.newOutput();
840     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.length);
841 
842     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
843     output.writeRawVarint32(tag);
844     output.writeRawVarint32(bytes.length);
845     output.writeRawBytes(bytes);
846     output.flush();
847 
848     byte[] rawInput = rawOutput.toByteString().toByteArray();
849     for (InputType inputType : InputType.values()) {
850       CodedInputStream input = inputType.newDecoder(rawInput);
851       assertEquals(inputType.name(), tag, input.readTag());
852       String text = input.readStringRequireUtf8();
853       assertEquals(inputType.name(), lorem, text);
854     }
855   }
856 
857   /**
858    * Tests that if we readString invalid UTF-8 bytes, no exception is thrown. Instead, the invalid
859    * bytes are replaced with the Unicode "replacement character" U+FFFD.
860    */
testReadStringInvalidUtf8()861   public void testReadStringInvalidUtf8() throws Exception {
862     ByteString.Output rawOutput = ByteString.newOutput();
863     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
864 
865     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
866     output.writeRawVarint32(tag);
867     output.writeRawVarint32(1);
868     output.writeRawBytes(new byte[] {(byte) 0x80});
869     output.flush();
870 
871     byte[] rawInput = rawOutput.toByteString().toByteArray();
872     for (InputType inputType : InputType.values()) {
873       CodedInputStream input = inputType.newDecoder(rawInput);
874       assertEquals(inputType.name(), tag, input.readTag());
875       String text = input.readString();
876       assertEquals(inputType.name(), 0xfffd, text.charAt(0));
877     }
878   }
879 
880   /**
881    * Tests that if we readStringRequireUtf8 invalid UTF-8 bytes, an InvalidProtocolBufferException
882    * is thrown.
883    */
testReadStringRequireUtf8InvalidUtf8()884   public void testReadStringRequireUtf8InvalidUtf8() throws Exception {
885     ByteString.Output rawOutput = ByteString.newOutput();
886     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
887 
888     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
889     output.writeRawVarint32(tag);
890     output.writeRawVarint32(1);
891     output.writeRawBytes(new byte[] {(byte) 0x80});
892     output.flush();
893 
894     byte[] rawInput = rawOutput.toByteString().toByteArray();
895     for (InputType inputType : InputType.values()) {
896       CodedInputStream input = inputType.newDecoder(rawInput);
897       assertEquals(tag, input.readTag());
898       try {
899         input.readStringRequireUtf8();
900         fail(inputType.name() + ": Expected invalid UTF-8 exception.");
901       } catch (InvalidProtocolBufferException exception) {
902         assertEquals(
903             inputType.name(), "Protocol message had invalid UTF-8.", exception.getMessage());
904       }
905     }
906   }
907 
testReadFromSlice()908   public void testReadFromSlice() throws Exception {
909     byte[] bytes = bytes(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
910     CodedInputStream in = CodedInputStream.newInstance(bytes, 3, 5);
911     assertEquals(0, in.getTotalBytesRead());
912     for (int i = 3; i < 8; i++) {
913       assertEquals(i, in.readRawByte());
914       assertEquals(i - 2, in.getTotalBytesRead());
915     }
916     // eof
917     assertEquals(0, in.readTag());
918     assertEquals(5, in.getTotalBytesRead());
919   }
920 
testInvalidTag()921   public void testInvalidTag() throws Exception {
922     // Any tag number which corresponds to field number zero is invalid and
923     // should throw InvalidProtocolBufferException.
924     for (InputType inputType : InputType.values()) {
925       for (int i = 0; i < 8; i++) {
926         try {
927           inputType.newDecoder(bytes(i)).readTag();
928           fail(inputType.name() + ": Should have thrown an exception.");
929         } catch (InvalidProtocolBufferException e) {
930           assertEquals(
931               inputType.name(),
932               InvalidProtocolBufferException.invalidTag().getMessage(),
933               e.getMessage());
934         }
935       }
936     }
937   }
938 
testReadByteArray()939   public void testReadByteArray() throws Exception {
940     ByteString.Output rawOutput = ByteString.newOutput();
941     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
942     // Zero-sized bytes field.
943     output.writeRawVarint32(0);
944     // One one-byte bytes field
945     output.writeRawVarint32(1);
946     output.writeRawBytes(new byte[] {(byte) 23});
947     // Another one-byte bytes field
948     output.writeRawVarint32(1);
949     output.writeRawBytes(new byte[] {(byte) 45});
950     // A bytes field large enough that won't fit into the 4K buffer.
951     final int bytesLength = 16 * 1024;
952     byte[] bytes = new byte[bytesLength];
953     bytes[0] = (byte) 67;
954     bytes[bytesLength - 1] = (byte) 89;
955     output.writeRawVarint32(bytesLength);
956     output.writeRawBytes(bytes);
957 
958     output.flush();
959 
960     byte[] rawInput = rawOutput.toByteString().toByteArray();
961     for (InputType inputType : InputType.values()) {
962       CodedInputStream inputStream = inputType.newDecoder(rawInput);
963 
964       byte[] result = inputStream.readByteArray();
965       assertEquals(inputType.name(), 0, result.length);
966       result = inputStream.readByteArray();
967       assertEquals(inputType.name(), 1, result.length);
968       assertEquals(inputType.name(), (byte) 23, result[0]);
969       result = inputStream.readByteArray();
970       assertEquals(inputType.name(), 1, result.length);
971       assertEquals(inputType.name(), (byte) 45, result[0]);
972       result = inputStream.readByteArray();
973       assertEquals(inputType.name(), bytesLength, result.length);
974       assertEquals(inputType.name(), (byte) 67, result[0]);
975       assertEquals(inputType.name(), (byte) 89, result[bytesLength - 1]);
976     }
977   }
978 
testReadLargeByteStringFromInputStream()979   public void testReadLargeByteStringFromInputStream() throws Exception {
980     byte[] bytes = new byte[1024 * 1024];
981     for (int i = 0; i < bytes.length; i++) {
982       bytes[i] = (byte) (i & 0xFF);
983     }
984     ByteString.Output rawOutput = ByteString.newOutput();
985     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
986     output.writeRawVarint32(bytes.length);
987     output.writeRawBytes(bytes);
988     output.flush();
989     byte[] data = rawOutput.toByteString().toByteArray();
990 
991     CodedInputStream input =
992         CodedInputStream.newInstance(
993             new ByteArrayInputStream(data) {
994               @Override
995               public synchronized int available() {
996                 return 0;
997               }
998             });
999     ByteString result = input.readBytes();
1000     assertEquals(ByteString.copyFrom(bytes), result);
1001   }
1002 
testReadLargeByteArrayFromInputStream()1003   public void testReadLargeByteArrayFromInputStream() throws Exception {
1004     byte[] bytes = new byte[1024 * 1024];
1005     for (int i = 0; i < bytes.length; i++) {
1006       bytes[i] = (byte) (i & 0xFF);
1007     }
1008     ByteString.Output rawOutput = ByteString.newOutput();
1009     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
1010     output.writeRawVarint32(bytes.length);
1011     output.writeRawBytes(bytes);
1012     output.flush();
1013     byte[] data = rawOutput.toByteString().toByteArray();
1014 
1015     CodedInputStream input =
1016         CodedInputStream.newInstance(
1017             new ByteArrayInputStream(data) {
1018               @Override
1019               public synchronized int available() {
1020                 return 0;
1021               }
1022             });
1023     byte[] result = input.readByteArray();
1024     assertTrue(Arrays.equals(bytes, result));
1025   }
1026 
testReadByteBuffer()1027   public void testReadByteBuffer() throws Exception {
1028     ByteString.Output rawOutput = ByteString.newOutput();
1029     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
1030     // Zero-sized bytes field.
1031     output.writeRawVarint32(0);
1032     // One one-byte bytes field
1033     output.writeRawVarint32(1);
1034     output.writeRawBytes(new byte[] {(byte) 23});
1035     // Another one-byte bytes field
1036     output.writeRawVarint32(1);
1037     output.writeRawBytes(new byte[] {(byte) 45});
1038     // A bytes field large enough that won't fit into the 4K buffer.
1039     final int bytesLength = 16 * 1024;
1040     byte[] bytes = new byte[bytesLength];
1041     bytes[0] = (byte) 67;
1042     bytes[bytesLength - 1] = (byte) 89;
1043     output.writeRawVarint32(bytesLength);
1044     output.writeRawBytes(bytes);
1045 
1046     output.flush();
1047 
1048     byte[] rawInput = rawOutput.toByteString().toByteArray();
1049     for (InputType inputType : InputType.values()) {
1050       CodedInputStream inputStream = inputType.newDecoder(rawInput);
1051 
1052       ByteBuffer result = inputStream.readByteBuffer();
1053       assertEquals(inputType.name(), 0, result.capacity());
1054       result = inputStream.readByteBuffer();
1055       assertEquals(inputType.name(), 1, result.capacity());
1056       assertEquals(inputType.name(), (byte) 23, result.get());
1057       result = inputStream.readByteBuffer();
1058       assertEquals(inputType.name(), 1, result.capacity());
1059       assertEquals(inputType.name(), (byte) 45, result.get());
1060       result = inputStream.readByteBuffer();
1061       assertEquals(inputType.name(), bytesLength, result.capacity());
1062       assertEquals(inputType.name(), (byte) 67, result.get());
1063       result.position(bytesLength - 1);
1064       assertEquals(inputType.name(), (byte) 89, result.get());
1065     }
1066   }
1067 
testReadByteBufferAliasing()1068   public void testReadByteBufferAliasing() throws Exception {
1069     ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream();
1070     CodedOutputStream output = CodedOutputStream.newInstance(byteArrayStream);
1071     // Zero-sized bytes field.
1072     output.writeRawVarint32(0);
1073     // One one-byte bytes field
1074     output.writeRawVarint32(1);
1075     output.writeRawBytes(new byte[] {(byte) 23});
1076     // Another one-byte bytes field
1077     output.writeRawVarint32(1);
1078     output.writeRawBytes(new byte[] {(byte) 45});
1079     // A bytes field large enough that won't fit into the 4K buffer.
1080     final int bytesLength = 16 * 1024;
1081     byte[] bytes = new byte[bytesLength];
1082     bytes[0] = (byte) 67;
1083     bytes[bytesLength - 1] = (byte) 89;
1084     output.writeRawVarint32(bytesLength);
1085     output.writeRawBytes(bytes);
1086     output.flush();
1087 
1088     byte[] data = byteArrayStream.toByteArray();
1089 
1090     for (InputType inputType : InputType.values()) {
1091       if (inputType == InputType.STREAM
1092           || inputType == InputType.STREAM_ITER_DIRECT
1093           || inputType == InputType.ITER_DIRECT) {
1094         // Aliasing doesn't apply to stream-backed CIS.
1095         continue;
1096       }
1097 
1098       // Without aliasing
1099       CodedInputStream inputStream = inputType.newDecoder(data);
1100       ByteBuffer result = inputStream.readByteBuffer();
1101       assertEquals(inputType.name(), 0, result.capacity());
1102       result = inputStream.readByteBuffer();
1103       assertTrue(inputType.name(), result.array() != data);
1104       assertEquals(inputType.name(), 1, result.capacity());
1105       assertEquals(inputType.name(), (byte) 23, result.get());
1106       result = inputStream.readByteBuffer();
1107       assertTrue(inputType.name(), result.array() != data);
1108       assertEquals(inputType.name(), 1, result.capacity());
1109       assertEquals(inputType.name(), (byte) 45, result.get());
1110       result = inputStream.readByteBuffer();
1111       assertTrue(inputType.name(), result.array() != data);
1112       assertEquals(inputType.name(), bytesLength, result.capacity());
1113       assertEquals(inputType.name(), (byte) 67, result.get());
1114       result.position(bytesLength - 1);
1115       assertEquals(inputType.name(), (byte) 89, result.get());
1116 
1117       // Enable aliasing
1118       inputStream = inputType.newDecoder(data, data.length);
1119       inputStream.enableAliasing(true);
1120       result = inputStream.readByteBuffer();
1121       assertEquals(inputType.name(), 0, result.capacity());
1122       result = inputStream.readByteBuffer();
1123       if (result.hasArray()) {
1124         assertTrue(inputType.name(), result.array() == data);
1125       }
1126       assertEquals(inputType.name(), 1, result.capacity());
1127       assertEquals(inputType.name(), (byte) 23, result.get());
1128       result = inputStream.readByteBuffer();
1129       if (result.hasArray()) {
1130         assertTrue(inputType.name(), result.array() == data);
1131       }
1132       assertEquals(inputType.name(), 1, result.capacity());
1133       assertEquals(inputType.name(), (byte) 45, result.get());
1134       result = inputStream.readByteBuffer();
1135       if (result.hasArray()) {
1136         assertTrue(inputType.name(), result.array() == data);
1137       }
1138       assertEquals(inputType.name(), bytesLength, result.capacity());
1139       assertEquals(inputType.name(), (byte) 67, result.get());
1140       result.position(bytesLength - 1);
1141       assertEquals(inputType.name(), (byte) 89, result.get());
1142     }
1143   }
1144 
testCompatibleTypes()1145   public void testCompatibleTypes() throws Exception {
1146     long data = 0x100000000L;
1147     Int64Message message = Int64Message.newBuilder().setData(data).build();
1148     byte[] serialized = message.toByteArray();
1149     for (InputType inputType : InputType.values()) {
1150       CodedInputStream inputStream = inputType.newDecoder(serialized);
1151 
1152       // Test int64(long) is compatible with bool(boolean)
1153       BoolMessage msg2 = BoolMessage.parseFrom(inputStream);
1154       assertTrue(msg2.getData());
1155 
1156       // Test int64(long) is compatible with int32(int)
1157       inputStream = inputType.newDecoder(serialized);
1158       Int32Message msg3 = Int32Message.parseFrom(inputStream);
1159       assertEquals((int) data, msg3.getData());
1160     }
1161   }
1162 
testSkipInvalidVarint_FastPath()1163   public void testSkipInvalidVarint_FastPath() throws Exception {
1164     // Fast path: We have >= 10 bytes available. Ensure we properly recognize a non-ending varint.
1165     byte[] data = new byte[] {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0};
1166     for (InputType inputType : InputType.values()) {
1167       try {
1168         CodedInputStream input = inputType.newDecoder(data);
1169         input.skipField(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT));
1170         fail(inputType.name() + ": Should have thrown an exception.");
1171       } catch (InvalidProtocolBufferException e) {
1172         // Expected
1173       }
1174     }
1175   }
1176 
testSkipInvalidVarint_SlowPath()1177   public void testSkipInvalidVarint_SlowPath() throws Exception {
1178     // Slow path: < 10 bytes available. Ensure we properly recognize a non-ending varint.
1179     byte[] data = new byte[] {-1, -1, -1, -1, -1, -1, -1, -1, -1};
1180     for (InputType inputType : InputType.values()) {
1181       try {
1182         CodedInputStream input = inputType.newDecoder(data);
1183         input.skipField(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT));
1184         fail(inputType.name() + ": Should have thrown an exception.");
1185       } catch (InvalidProtocolBufferException e) {
1186         // Expected
1187       }
1188     }
1189   }
1190 
testSkipPastEndOfByteArrayInput()1191   public void testSkipPastEndOfByteArrayInput() throws Exception {
1192     try {
1193       CodedInputStream.newInstance(new ByteArrayInputStream(new byte[100])).skipRawBytes(101);
1194       fail();
1195     } catch (InvalidProtocolBufferException e) {
1196       // Expected
1197     }
1198   }
1199 
testMaliciousInputStream()1200   public void testMaliciousInputStream() throws Exception {
1201     ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
1202     CodedOutputStream codedOutputStream = CodedOutputStream.newInstance(outputStream);
1203     codedOutputStream.writeByteArrayNoTag(new byte[] { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5 });
1204     codedOutputStream.flush();
1205     final List<byte[]> maliciousCapture = new ArrayList<>();
1206     InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()) {
1207       @Override
1208       public synchronized int read(byte[] b, int off, int len) {
1209         maliciousCapture.add(b);
1210         return super.read(b, off, len);
1211       }
1212     };
1213 
1214     // test ByteString
1215 
1216     CodedInputStream codedInputStream = CodedInputStream.newInstance(inputStream, 1);
1217     ByteString byteString = codedInputStream.readBytes();
1218     assertEquals(0x0, byteString.byteAt(0));
1219     maliciousCapture.get(1)[0] = 0x9;
1220     assertEquals(0x0, byteString.byteAt(0));
1221 
1222     // test ByteBuffer
1223 
1224     inputStream.reset();
1225     maliciousCapture.clear();
1226     codedInputStream = CodedInputStream.newInstance(inputStream, 1);
1227     ByteBuffer byteBuffer = codedInputStream.readByteBuffer();
1228     assertEquals(0x0, byteBuffer.get(0));
1229     maliciousCapture.get(1)[0] = 0x9;
1230     assertEquals(0x0, byteBuffer.get(0));
1231 
1232 
1233     // test byte[]
1234 
1235     inputStream.reset();
1236     maliciousCapture.clear();
1237     codedInputStream = CodedInputStream.newInstance(inputStream, 1);
1238     byte[] byteArray = codedInputStream.readByteArray();
1239     assertEquals(0x0, byteArray[0]);
1240     maliciousCapture.get(1)[0] = 0x9;
1241     assertEquals(0x9, byteArray[0]); // MODIFICATION! Should we fix?
1242 
1243     // test rawBytes
1244 
1245     inputStream.reset();
1246     maliciousCapture.clear();
1247     codedInputStream = CodedInputStream.newInstance(inputStream, 1);
1248     int length = codedInputStream.readRawVarint32();
1249     byteArray = codedInputStream.readRawBytes(length);
1250     assertEquals(0x0, byteArray[0]);
1251     maliciousCapture.get(1)[0] = 0x9;
1252     assertEquals(0x9, byteArray[0]); // MODIFICATION! Should we fix?
1253   }
1254 }
1255