1 /* 2 * Copyright (C) 2020 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 com.android.test.protoinputstream; 18 19 import android.util.proto.ProtoInputStream; 20 import android.util.proto.ProtoParseException; 21 import android.util.proto.ProtoStream; 22 23 import junit.framework.TestCase; 24 25 import java.io.ByteArrayInputStream; 26 import java.io.IOException; 27 import java.io.InputStream; 28 29 public class ProtoInputStreamIncompleteValueTest extends TestCase { 30 31 /** 32 * Test that an incomplete varint at the end of a stream throws an exception 33 */ testIncompleteVarint()34 public void testIncompleteVarint() throws IOException { 35 final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_INT32; 36 37 final long fieldId1 = fieldFlags | ((long) 1 & 0x0ffffffffL); 38 39 final byte[] protobuf = new byte[]{ 40 // 1 : varint -> invalid varint value 41 (byte) 0x08, 42 (byte) 0xff, 43 }; 44 45 InputStream stream = new ByteArrayInputStream(protobuf); 46 final ProtoInputStream pi = new ProtoInputStream(stream); 47 48 while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) { 49 try { 50 switch (pi.getFieldNumber()) { 51 case (int) fieldId1: 52 pi.readInt(fieldId1); 53 fail("Should have thrown a ProtoParseException"); 54 break; 55 default: 56 fail("Unexpected field id " + pi.getFieldNumber()); 57 } 58 } catch (ProtoParseException ppe) { 59 // good 60 stream.close(); 61 return; 62 } 63 } 64 stream.close(); 65 fail("Test should not have reached this point..."); 66 } 67 68 /** 69 * Test that an incomplete fixed64 at the end of a stream throws an exception 70 */ testIncompleteFixed64()71 public void testIncompleteFixed64() throws IOException { 72 final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED64; 73 74 final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL); 75 76 final byte[] protobuf = new byte[]{ 77 // 2 -> invalid fixed64 78 (byte) 0x11, 79 (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, 80 (byte) 0x00, (byte) 0x00, (byte) 0x00, 81 }; 82 83 InputStream stream = new ByteArrayInputStream(protobuf); 84 final ProtoInputStream pi = new ProtoInputStream(stream); 85 86 while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) { 87 try { 88 switch (pi.getFieldNumber()) { 89 case (int) fieldId2: 90 pi.readLong(fieldId2); 91 fail("Should have thrown a ProtoParseException"); 92 break; 93 default: 94 fail("Unexpected field id " + pi.getFieldNumber()); 95 } 96 } catch (ProtoParseException ppe) { 97 // good 98 stream.close(); 99 return; 100 } 101 } 102 stream.close(); 103 fail("Test should not have reached this point..."); 104 } 105 106 /** 107 * Test that an incomplete length delimited value at the end of a stream throws an exception 108 */ testIncompleteLengthDelimited()109 public void testIncompleteLengthDelimited() throws IOException { 110 final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_BYTES; 111 112 final long fieldId5 = fieldFlags | ((long) 5 & 0x0ffffffffL); 113 114 final byte[] protobuf = new byte[]{ 115 // 5 -> invalid byte array (has size 5 but only 4 values) 116 (byte) 0x2a, 117 (byte) 0x05, 118 (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x03, 119 }; 120 121 InputStream stream = new ByteArrayInputStream(protobuf); 122 final ProtoInputStream pi = new ProtoInputStream(stream); 123 124 while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) { 125 try { 126 switch (pi.getFieldNumber()) { 127 case (int) fieldId5: 128 pi.readBytes(fieldId5); 129 fail("Should have thrown a ProtoParseException"); 130 break; 131 default: 132 fail("Unexpected field id " + pi.getFieldNumber()); 133 } 134 } catch (ProtoParseException ppe) { 135 // good 136 stream.close(); 137 return; 138 } 139 } 140 stream.close(); 141 fail("Test should not have reached this point..."); 142 } 143 144 /** 145 * Test that an incomplete fixed32 at the end of a stream throws an exception 146 */ testIncompleteFixed32()147 public void testIncompleteFixed32() throws IOException { 148 final long fieldFlags = ProtoStream.FIELD_COUNT_SINGLE | ProtoStream.FIELD_TYPE_FIXED32; 149 150 final long fieldId2 = fieldFlags | ((long) 2 & 0x0ffffffffL); 151 152 final byte[] protobuf = new byte[]{ 153 // 2 -> invalid fixed32 154 (byte) 0x15, 155 (byte) 0x01, (byte) 0x00, (byte) 0x00, 156 }; 157 158 InputStream stream = new ByteArrayInputStream(protobuf); 159 final ProtoInputStream pi = new ProtoInputStream(stream); 160 161 while (pi.nextField() != ProtoInputStream.NO_MORE_FIELDS) { 162 try { 163 switch (pi.getFieldNumber()) { 164 case (int) fieldId2: 165 pi.readInt(fieldId2); 166 fail("Should have thrown a ProtoParseException"); 167 break; 168 default: 169 fail("Unexpected field id " + pi.getFieldNumber()); 170 } 171 } catch (ProtoParseException ppe) { 172 // good 173 stream.close(); 174 return; 175 } 176 } 177 stream.close(); 178 fail("Test should not have reached this point..."); 179 } 180 } 181