blob: 580e95915d866c1f9a54fb3192fb470a5f0d9901 [file] [log] [blame]
Lalit Maganti45172a82018-06-01 03:04:43 +01001/*
Lalit Magantic6bccda2018-06-25 11:05:24 +01002 * Copyright (C) 2018 The Android Open Source Project
Lalit Maganti45172a82018-06-01 03:04:43 +01003 *
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#include "perfetto/protozero/proto_decoder.h"
18
Primiano Tucci2c5488f2019-06-01 03:27:28 +010019#include "perfetto/ext/base/utils.h"
Lalit Maganti45172a82018-06-01 03:04:43 +010020#include "perfetto/protozero/message.h"
21#include "perfetto/protozero/proto_utils.h"
Eric Seckler76311202019-01-07 12:20:25 +000022#include "perfetto/protozero/scattered_heap_buffer.h"
Primiano Tucci2cfc7fd2019-11-28 16:07:27 +000023#include "perfetto/protozero/static_buffer.h"
Primiano Tucci919ca1e2019-08-21 20:26:58 +020024#include "test/gtest_and_gmock.h"
Lalit Maganti45172a82018-06-01 03:04:43 +010025
Ryancbd16152019-09-04 16:54:45 +010026#include "src/protozero/test/example_proto/test_messages.pb.h"
27#include "src/protozero/test/example_proto/test_messages.pbzero.h"
28
Primiano Tucciba784e52019-11-13 07:04:52 -080029// Generated by the protozero plugin.
30namespace pbtest = protozero::test::protos::pbzero;
31
32// Generated by the official protobuf compiler.
33namespace pbgold = protozero::test::protos;
Ryancbd16152019-09-04 16:54:45 +010034
Lalit Maganti45172a82018-06-01 03:04:43 +010035namespace protozero {
36namespace {
37
38using ::testing::_;
39using ::testing::InSequence;
40using ::testing::Invoke;
Isabelle Tayloraa45fe02018-12-16 21:02:20 +000041using namespace proto_utils;
Lalit Maganti45172a82018-06-01 03:04:43 +010042
Primiano Tuccic1678872019-03-20 11:30:54 +000043TEST(ProtoDecoderTest, ReadString) {
Primiano Tuccia2d75e92019-05-17 12:06:30 +010044 HeapBuffered<Message> message;
Lalit Maganti45172a82018-06-01 03:04:43 +010045
46 static constexpr char kTestString[] = "test";
Primiano Tuccia2d75e92019-05-17 12:06:30 +010047 message->AppendString(1, kTestString);
48 std::vector<uint8_t> proto = message.SerializeAsArray();
49 TypedProtoDecoder<32, false> decoder(proto.data(), proto.size());
Lalit Maganti45172a82018-06-01 03:04:43 +010050
Primiano Tuccic1678872019-03-20 11:30:54 +000051 const auto& field = decoder.Get(1);
52 ASSERT_EQ(field.type(), ProtoWireType::kLengthDelimited);
53 ASSERT_EQ(field.size(), sizeof(kTestString) - 1);
Lalit Maganti45172a82018-06-01 03:04:43 +010054 for (size_t i = 0; i < sizeof(kTestString) - 1; i++) {
Primiano Tuccic1678872019-03-20 11:30:54 +000055 ASSERT_EQ(field.data()[i], kTestString[i]);
Lalit Maganti45172a82018-06-01 03:04:43 +010056 }
57}
58
Primiano Tucci2cfc7fd2019-11-28 16:07:27 +000059TEST(ProtoDecoderTest, SkipVeryLargeFields) {
60 const size_t kPayloadSize = 257 * 1024 * 1024;
61 const uint64_t data_size = 4096 + kPayloadSize;
Hector Dearmancf4ef4b2019-02-27 19:10:21 +000062 std::unique_ptr<uint8_t, perfetto::base::FreeDeleter> data(
Primiano Tucci2cfc7fd2019-11-28 16:07:27 +000063 static_cast<uint8_t*>(malloc(data_size)));
Hector Dearmancf4ef4b2019-02-27 19:10:21 +000064
Primiano Tucci2cfc7fd2019-11-28 16:07:27 +000065 StaticBufferDelegate delegate(data.get(), data_size);
66 ScatteredStreamWriter writer(&delegate);
67 Message message;
68 message.Reset(&writer);
Hector Dearmancf4ef4b2019-02-27 19:10:21 +000069
Primiano Tucci2cfc7fd2019-11-28 16:07:27 +000070 // Append a valid field.
71 message.AppendVarInt(/*field_id=*/1, 11);
72
73 // Append a very large field that will be skipped.
74 uint8_t raw[10];
75 uint8_t* wptr = raw;
76 wptr = WriteVarInt(MakeTagLengthDelimited(2), wptr);
77 wptr = WriteVarInt(kPayloadSize, wptr);
78 message.AppendRawProtoBytes(raw, static_cast<size_t>(wptr - raw));
79 const uint8_t padding[1024 * 128]{};
80 for (size_t i = 0; i < kPayloadSize / sizeof(padding); i++)
81 message.AppendRawProtoBytes(padding, sizeof(padding));
82
83 // Append another valid field.
84 message.AppendVarInt(/*field_id=*/3, 13);
85
86 ProtoDecoder decoder(data.get(), static_cast<size_t>(writer.written()));
Primiano Tuccic1678872019-03-20 11:30:54 +000087 Field field = decoder.ReadField();
88 ASSERT_EQ(1u, field.id());
Primiano Tucci2cfc7fd2019-11-28 16:07:27 +000089 ASSERT_EQ(11, field.as_int32());
90
91 field = decoder.ReadField();
92 ASSERT_EQ(3u, field.id());
93 ASSERT_EQ(13, field.as_int32());
94
95 field = decoder.ReadField();
96 ASSERT_FALSE(field.valid());
Hector Dearmancf4ef4b2019-02-27 19:10:21 +000097}
98
Hector Dearmanc7c267a2019-03-25 13:06:21 +000099TEST(ProtoDecoderTest, SingleRepeatedField) {
100 Message message;
101 ScatteredHeapBuffer delegate(512, 512);
102 ScatteredStreamWriter writer(&delegate);
103 delegate.set_writer(&writer);
104 message.Reset(&writer);
105 message.AppendVarInt(/*field_id=*/2, 10);
106 delegate.AdjustUsedSizeOfCurrentSlice();
107 auto used_range = delegate.slices()[0].GetUsedRange();
108
109 TypedProtoDecoder<2, true> tpd(used_range.begin, used_range.size());
Primiano Tucci8f7359c2019-10-17 12:59:33 +0100110 auto it = tpd.GetRepeated<int32_t>(/*field_id=*/2);
Hector Dearmanc7c267a2019-03-25 13:06:21 +0000111 EXPECT_TRUE(it);
Primiano Tucci8f7359c2019-10-17 12:59:33 +0100112 EXPECT_EQ(it.field().as_int32(), 10);
113 EXPECT_EQ(*it, 10);
Hector Dearmanc7c267a2019-03-25 13:06:21 +0000114 EXPECT_FALSE(++it);
115}
116
Sami Kyostila8a48e022019-11-12 23:46:18 +0000117TEST(ProtoDecoderTest, RepeatedVariableLengthField) {
118 HeapBuffered<Message> message;
119
120 static constexpr char kTestString[] = "test";
121 static constexpr char kTestString2[] = "honk honk";
122 message->AppendString(1, kTestString);
123 message->AppendString(1, kTestString2);
124 std::vector<uint8_t> proto = message.SerializeAsArray();
125 TypedProtoDecoder<32, false> decoder(proto.data(), proto.size());
126
127 auto it = decoder.GetRepeated<ConstChars>(1);
128 ASSERT_EQ(it->type(), ProtoWireType::kLengthDelimited);
129 ASSERT_EQ(it->size(), sizeof(kTestString) - 1);
130 ASSERT_EQ(it->as_std_string(), std::string(kTestString));
131 ASSERT_EQ((*it).ToStdString(), std::string(kTestString));
132 ++it;
133 ASSERT_EQ(it->type(), ProtoWireType::kLengthDelimited);
134 ASSERT_EQ(it->size(), sizeof(kTestString2) - 1);
135 ASSERT_EQ(it->as_std_string(), std::string(kTestString2));
136 ASSERT_EQ((*it).ToStdString(), std::string(kTestString2));
137}
138
Hector Dearmanc7c267a2019-03-25 13:06:21 +0000139TEST(ProtoDecoderTest, SingleRepeatedFieldWithExpansion) {
140 Message message;
141 ScatteredHeapBuffer delegate(512, 512);
142 ScatteredStreamWriter writer(&delegate);
143 delegate.set_writer(&writer);
144 message.Reset(&writer);
145 for (int i = 0; i < 2000; i++) {
146 message.AppendVarInt(/*field_id=*/2, i);
147 }
148 std::vector<uint8_t> data = delegate.StitchSlices();
149
150 TypedProtoDecoder<2, true> tpd(data.data(), data.size());
Primiano Tucci8f7359c2019-10-17 12:59:33 +0100151 auto it = tpd.GetRepeated<int32_t>(/*field_id=*/2);
Hector Dearmanc7c267a2019-03-25 13:06:21 +0000152 for (int i = 0; i < 2000; i++) {
153 EXPECT_TRUE(it);
Primiano Tucci8f7359c2019-10-17 12:59:33 +0100154 EXPECT_EQ(*it, i);
Hector Dearmanc7c267a2019-03-25 13:06:21 +0000155 ++it;
156 }
157 EXPECT_FALSE(it);
158}
159
160TEST(ProtoDecoderTest, NoRepeatedField) {
161 uint8_t buf[] = {0x01};
162 TypedProtoDecoder<2, true> tpd(buf, 1);
Primiano Tucci8f7359c2019-10-17 12:59:33 +0100163 auto it = tpd.GetRepeated<int32_t>(/*field_id=*/1);
Hector Dearmanc7c267a2019-03-25 13:06:21 +0000164 EXPECT_FALSE(it);
165 EXPECT_FALSE(tpd.Get(2).valid());
166}
167
168TEST(ProtoDecoderTest, RepeatedFields) {
169 Message message;
170 ScatteredHeapBuffer delegate(512, 512);
171 ScatteredStreamWriter writer(&delegate);
172 delegate.set_writer(&writer);
173 message.Reset(&writer);
174
175 message.AppendVarInt(1, 10);
176 message.AppendVarInt(2, 20);
177 message.AppendVarInt(3, 30);
178
179 message.AppendVarInt(1, 11);
180 message.AppendVarInt(2, 21);
181 message.AppendVarInt(2, 22);
182
183 delegate.AdjustUsedSizeOfCurrentSlice();
184 auto used_range = delegate.slices()[0].GetUsedRange();
185
186 // When iterating with the simple decoder we should just see fields in parsing
187 // order.
188 ProtoDecoder decoder(used_range.begin, used_range.size());
189 std::string fields_seen;
190 for (auto fld = decoder.ReadField(); fld.valid(); fld = decoder.ReadField()) {
191 fields_seen +=
192 std::to_string(fld.id()) + ":" + std::to_string(fld.as_int32()) + ";";
193 }
194 EXPECT_EQ(fields_seen, "1:10;2:20;3:30;1:11;2:21;2:22;");
195
196 TypedProtoDecoder<4, true> tpd(used_range.begin, used_range.size());
197
198 // When parsing with the one-shot decoder and querying the single field id, we
199 // should see the last value for each of them, not the first one. This is the
200 // current behavior of Google protobuf's parser.
201 EXPECT_EQ(tpd.Get(1).as_int32(), 11);
202 EXPECT_EQ(tpd.Get(2).as_int32(), 22);
203 EXPECT_EQ(tpd.Get(3).as_int32(), 30);
204
205 // But when iterating we should see values in the original order.
Primiano Tucci8f7359c2019-10-17 12:59:33 +0100206 auto it = tpd.GetRepeated<int32_t>(1);
207 EXPECT_EQ(*it, 10);
208 EXPECT_EQ(*++it, 11);
Hector Dearmanc7c267a2019-03-25 13:06:21 +0000209 EXPECT_FALSE(++it);
210
Primiano Tucci8f7359c2019-10-17 12:59:33 +0100211 it = tpd.GetRepeated<int32_t>(2);
212 EXPECT_EQ(*it++, 20);
213 EXPECT_EQ(*it++, 21);
214 EXPECT_EQ(*it++, 22);
Sami Kyostila5b509202019-07-24 07:15:50 +0100215 EXPECT_FALSE(it);
Hector Dearmanc7c267a2019-03-25 13:06:21 +0000216
Primiano Tucci8f7359c2019-10-17 12:59:33 +0100217 it = tpd.GetRepeated<int32_t>(3);
218 EXPECT_EQ(*it, 30);
Hector Dearmanc7c267a2019-03-25 13:06:21 +0000219 EXPECT_FALSE(++it);
220}
221
Primiano Tuccic1678872019-03-20 11:30:54 +0000222TEST(ProtoDecoderTest, FixedData) {
Lalit Maganti45172a82018-06-01 03:04:43 +0100223 struct FieldExpectation {
224 const char* encoded;
225 size_t encoded_size;
226 uint32_t id;
Isabelle Tayloraa45fe02018-12-16 21:02:20 +0000227 ProtoWireType type;
Lalit Maganti45172a82018-06-01 03:04:43 +0100228 uint64_t int_value;
229 };
230
231 const FieldExpectation kFieldExpectations[] = {
Isabelle Tayloraa45fe02018-12-16 21:02:20 +0000232 {"\x08\x00", 2, 1, ProtoWireType::kVarInt, 0},
Hector Dearmandd639792019-01-31 15:04:59 +0000233 {"\x08\x01", 2, 1, ProtoWireType::kVarInt, 1},
Isabelle Tayloraa45fe02018-12-16 21:02:20 +0000234 {"\x08\x42", 2, 1, ProtoWireType::kVarInt, 0x42},
235 {"\xF8\x07\x42", 3, 127, ProtoWireType::kVarInt, 0x42},
Primiano Tuccic1678872019-03-20 11:30:54 +0000236 {"\xB8\x3E\xFF\xFF\xFF\xFF\x0F", 7, 999, ProtoWireType::kVarInt,
Isabelle Tayloraa45fe02018-12-16 21:02:20 +0000237 0xFFFFFFFF},
238 {"\x7D\x42\x00\x00\x00", 5, 15, ProtoWireType::kFixed32, 0x42},
Primiano Tuccic1678872019-03-20 11:30:54 +0000239 {"\xBD\x3E\x78\x56\x34\x12", 6, 999, ProtoWireType::kFixed32, 0x12345678},
Isabelle Tayloraa45fe02018-12-16 21:02:20 +0000240 {"\x79\x42\x00\x00\x00\x00\x00\x00\x00", 9, 15, ProtoWireType::kFixed64,
241 0x42},
Primiano Tuccic1678872019-03-20 11:30:54 +0000242 {"\xB9\x3E\x08\x07\x06\x05\x04\x03\x02\x01", 10, 999,
Isabelle Tayloraa45fe02018-12-16 21:02:20 +0000243 ProtoWireType::kFixed64, 0x0102030405060708},
244 {"\x0A\x00", 2, 1, ProtoWireType::kLengthDelimited, 0},
245 {"\x0A\x04|abc", 6, 1, ProtoWireType::kLengthDelimited, 4},
Primiano Tuccic1678872019-03-20 11:30:54 +0000246 {"\xBA\x3E\x04|abc", 7, 999, ProtoWireType::kLengthDelimited, 4},
247 {"\xBA\x3E\x83\x01|abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzab"
Lalit Maganti45172a82018-06-01 03:04:43 +0100248 "cdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu"
249 "vwx",
Primiano Tuccic1678872019-03-20 11:30:54 +0000250 135, 999, ProtoWireType::kLengthDelimited, 131},
Lalit Maganti45172a82018-06-01 03:04:43 +0100251 };
252
253 for (size_t i = 0; i < perfetto::base::ArraySize(kFieldExpectations); ++i) {
254 const FieldExpectation& exp = kFieldExpectations[i];
Primiano Tuccic1678872019-03-20 11:30:54 +0000255 TypedProtoDecoder<999, 0> decoder(
256 reinterpret_cast<const uint8_t*>(exp.encoded), exp.encoded_size);
Lalit Maganti45172a82018-06-01 03:04:43 +0100257
Primiano Tuccic1678872019-03-20 11:30:54 +0000258 auto& field = decoder.Get(exp.id);
259 ASSERT_EQ(exp.type, field.type());
Lalit Maganti45172a82018-06-01 03:04:43 +0100260
Primiano Tuccic1678872019-03-20 11:30:54 +0000261 if (field.type() == ProtoWireType::kLengthDelimited) {
262 ASSERT_EQ(exp.int_value, field.size());
Lalit Maganti45172a82018-06-01 03:04:43 +0100263 } else {
Oystein Eftevaagf159a212019-03-22 15:39:08 -0700264 ASSERT_EQ(int64_t(exp.int_value), field.as_int64());
Hector Dearmandd639792019-01-31 15:04:59 +0000265 // Proto encodes booleans as varints of 0 or 1.
266 if (exp.int_value == 0 || exp.int_value == 1) {
Florian Mayer15aac0c2019-03-22 11:15:30 +0000267 ASSERT_EQ(int64_t(exp.int_value), field.as_bool());
Hector Dearmandd639792019-01-31 15:04:59 +0000268 }
Lalit Maganti45172a82018-06-01 03:04:43 +0100269 }
270 }
Primiano Tuccic1678872019-03-20 11:30:54 +0000271
272 // Test float and doubles decoding.
273 const char buf[] = "\x0d\x00\x00\xa0\x3f\x11\x00\x00\x00\x00\x00\x42\x8f\xc0";
Ryancbd16152019-09-04 16:54:45 +0100274 TypedProtoDecoder<2, false> decoder(reinterpret_cast<const uint8_t*>(buf),
275 sizeof(buf));
Primiano Tuccic1678872019-03-20 11:30:54 +0000276 EXPECT_FLOAT_EQ(decoder.Get(1).as_float(), 1.25f);
277 EXPECT_DOUBLE_EQ(decoder.Get(2).as_double(), -1000.25);
Lalit Maganti45172a82018-06-01 03:04:43 +0100278}
279
Eric Secklerd0125972019-04-29 09:49:22 +0000280TEST(ProtoDecoderTest, FindField) {
281 uint8_t buf[] = {0x08, 0x00}; // field_id 1, varint value 0.
282 ProtoDecoder pd(buf, 2);
283
284 auto field = pd.FindField(1);
285 ASSERT_TRUE(field);
286 EXPECT_EQ(field.as_int64(), 0);
287
288 auto field2 = pd.FindField(2);
289 EXPECT_FALSE(field2);
290}
291
Sami Kyostilac45e9452019-07-26 23:42:28 +0100292TEST(ProtoDecoderTest, MoveTypedDecoder) {
293 HeapBuffered<Message> message;
294 message->AppendVarInt(/*field_id=*/1, 10);
295 std::vector<uint8_t> proto = message.SerializeAsArray();
296
297 // Construct a decoder that uses inline storage (i.e., the fields are stored
298 // within the object itself).
299 using Decoder = TypedProtoDecoder<32, false>;
300 std::unique_ptr<Decoder> decoder(new Decoder(proto.data(), proto.size()));
301 ASSERT_GE(reinterpret_cast<uintptr_t>(&decoder->at<1>()),
302 reinterpret_cast<uintptr_t>(decoder.get()));
303 ASSERT_LT(reinterpret_cast<uintptr_t>(&decoder->at<1>()),
304 reinterpret_cast<uintptr_t>(decoder.get()) + sizeof(Decoder));
305
306 // Move the decoder into another object and deallocate the original object.
307 Decoder decoder2(std::move(*decoder));
308 decoder.reset();
309
310 // Check that the contents got moved correctly.
311 EXPECT_EQ(decoder2.Get(1).as_int32(), 10);
312 ASSERT_GE(reinterpret_cast<uintptr_t>(&decoder2.at<1>()),
313 reinterpret_cast<uintptr_t>(&decoder2));
314 ASSERT_LT(reinterpret_cast<uintptr_t>(&decoder2.at<1>()),
315 reinterpret_cast<uintptr_t>(&decoder2) + sizeof(Decoder));
316}
317
Ryancbd16152019-09-04 16:54:45 +0100318TEST(ProtoDecoderTest, PackedRepeatedVarint) {
319 std::vector<int32_t> values = {42, 255, 0, -1};
320
321 // serialize using protobuf library
322 pbgold::PackedRepeatedFields msg;
323 for (auto v : values)
324 msg.add_field_int32(v);
325 std::string serialized = msg.SerializeAsString();
326
327 // decode using TypedProtoDecoder directly
328 {
329 constexpr int kFieldId =
330 pbtest::PackedRepeatedFields::kFieldInt32FieldNumber;
331 TypedProtoDecoder<kFieldId, false> decoder(
332 reinterpret_cast<const uint8_t*>(serialized.data()), serialized.size());
333 ASSERT_TRUE(decoder.at<kFieldId>().valid());
334 bool parse_error = false;
335 auto packed_it =
336 decoder.GetPackedRepeated<proto_utils::ProtoWireType::kVarInt, int32_t>(
337 kFieldId, &parse_error);
338
339 std::vector<int32_t> decoded_values;
340 for (; packed_it; ++packed_it) {
341 auto v = *packed_it;
342 decoded_values.push_back(v);
343 }
344 ASSERT_EQ(values, decoded_values);
345 ASSERT_FALSE(parse_error);
346 }
347
348 // decode using plugin-generated accessor
349 {
350 auto decoder = pbtest::PackedRepeatedFields::Decoder(serialized);
351 ASSERT_TRUE(decoder.has_field_int32());
352
353 bool parse_error = false;
354 std::vector<int32_t> decoded_values;
355 for (auto packed_it = decoder.field_int32(&parse_error); packed_it;
356 ++packed_it) {
357 auto v = *packed_it;
358 decoded_values.push_back(v);
359 }
360 ASSERT_EQ(values, decoded_values);
361 ASSERT_FALSE(parse_error);
362 }
363
364 // unset field case
365 pbgold::PackedRepeatedFields empty_msg;
366 std::string empty_serialized = empty_msg.SerializeAsString();
367 auto decoder = pbtest::PackedRepeatedFields::Decoder(empty_serialized);
368 ASSERT_FALSE(decoder.has_field_int32());
369 bool parse_error = false;
370 auto packed_it = decoder.field_int32(&parse_error);
371 ASSERT_FALSE(bool(packed_it));
372 ASSERT_FALSE(parse_error);
373}
374
375TEST(ProtoDecoderTest, PackedRepeatedFixed32) {
376 std::vector<uint32_t> values = {42, 255, 0, 1};
377
378 // serialize using protobuf library
379 pbgold::PackedRepeatedFields msg;
380 for (auto v : values)
381 msg.add_field_fixed32(v);
382 std::string serialized = msg.SerializeAsString();
383
384 // decode using TypedProtoDecoder directly
385 {
386 constexpr int kFieldId =
387 pbtest::PackedRepeatedFields::kFieldFixed32FieldNumber;
388 TypedProtoDecoder<kFieldId, false> decoder(
389 reinterpret_cast<const uint8_t*>(serialized.data()), serialized.size());
390 bool parse_error = false;
391 auto packed_it =
392 decoder
393 .GetPackedRepeated<proto_utils::ProtoWireType::kFixed32, uint32_t>(
394 kFieldId, &parse_error);
395
396 std::vector<uint32_t> decoded_values;
397 for (; packed_it; ++packed_it) {
398 auto v = *packed_it;
399 decoded_values.push_back(v);
400 }
401 ASSERT_EQ(values, decoded_values);
402 ASSERT_FALSE(parse_error);
403 }
404
405 // decode using plugin-generated accessor
406 {
407 auto decoder = pbtest::PackedRepeatedFields::Decoder(serialized);
408 ASSERT_TRUE(decoder.has_field_fixed32());
409
410 bool parse_error = false;
411 std::vector<uint32_t> decoded_values;
412 for (auto packed_it = decoder.field_fixed32(&parse_error); packed_it;
413 packed_it++) {
414 auto v = *packed_it;
415 decoded_values.push_back(v);
416 }
417 ASSERT_EQ(values, decoded_values);
418 ASSERT_FALSE(parse_error);
419 }
420
421 // unset field case
422 pbgold::PackedRepeatedFields empty_msg;
423 std::string empty_serialized = empty_msg.SerializeAsString();
424 auto decoder = pbtest::PackedRepeatedFields::Decoder(empty_serialized);
425 ASSERT_FALSE(decoder.has_field_fixed32());
426 bool parse_error = false;
427 auto packed_it = decoder.field_fixed32(&parse_error);
428 ASSERT_FALSE(bool(packed_it));
429 ASSERT_FALSE(parse_error);
430}
431
432TEST(ProtoDecoderTest, PackedRepeatedFixed64) {
433 std::vector<int64_t> values = {42, 255, 0, -1};
434
435 // serialize using protobuf library
436 pbgold::PackedRepeatedFields msg;
437 for (auto v : values)
438 msg.add_field_sfixed64(v);
439 std::string serialized = msg.SerializeAsString();
440
441 // decode using TypedProtoDecoder directly
442 {
443 constexpr int kFieldId =
444 pbtest::PackedRepeatedFields::kFieldSfixed64FieldNumber;
445 TypedProtoDecoder<kFieldId, false> decoder(
446 reinterpret_cast<const uint8_t*>(serialized.data()), serialized.size());
447 bool parse_error = false;
448 auto packed_it =
449 decoder
450 .GetPackedRepeated<proto_utils::ProtoWireType::kFixed64, int64_t>(
451 kFieldId, &parse_error);
452
453 std::vector<int64_t> decoded_values;
454 for (; packed_it; ++packed_it) {
455 auto v = *packed_it;
456 decoded_values.push_back(v);
457 }
458 ASSERT_EQ(values, decoded_values);
459 ASSERT_FALSE(parse_error);
460 }
461
462 // decode using plugin-generated accessor
463 {
464 auto decoder = pbtest::PackedRepeatedFields::Decoder(serialized);
465 ASSERT_TRUE(decoder.has_field_sfixed64());
466
467 bool parse_error = false;
468 std::vector<int64_t> decoded_values;
469 for (auto packed_it = decoder.field_sfixed64(&parse_error); packed_it;
470 packed_it++) {
471 auto v = *packed_it;
472 decoded_values.push_back(v);
473 }
474 ASSERT_EQ(values, decoded_values);
475 ASSERT_FALSE(parse_error);
476 }
477
478 // unset field case
479 pbgold::PackedRepeatedFields empty_msg;
480 std::string empty_serialized = empty_msg.SerializeAsString();
481 auto decoder = pbtest::PackedRepeatedFields::Decoder(empty_serialized);
482 ASSERT_FALSE(decoder.has_field_sfixed64());
483 bool parse_error = false;
484 auto packed_it = decoder.field_sfixed64(&parse_error);
485 ASSERT_FALSE(bool(packed_it));
486 ASSERT_FALSE(parse_error);
487}
488
489TEST(ProtoDecoderTest, ZeroLengthPackedRepeatedField) {
490 HeapBuffered<pbtest::PackedRepeatedFields> msg;
Primiano Tucci03ac8332019-11-06 13:30:36 +0000491 PackedVarInt buf;
Ryancbd16152019-09-04 16:54:45 +0100492 msg->set_field_int32(buf);
493 std::string serialized = msg.SerializeAsString();
494
495 // Encoded as 2 bytes: tag/field, and a length of zero.
496 EXPECT_EQ(2u, serialized.size());
497
498 // Appears empty when decoded.
499 auto decoder = pbtest::PackedRepeatedFields::Decoder(serialized);
500 ASSERT_TRUE(decoder.has_field_int32());
501 bool parse_error = false;
502 auto packed_it = decoder.field_int32(&parse_error);
503 ASSERT_FALSE(bool(packed_it));
504 ASSERT_FALSE(parse_error);
505}
506
507TEST(ProtoDecoderTest, MalformedPackedFixedBuffer) {
508 // Encode a fixed32 field where the length is not a multiple of 4 bytes.
509 HeapBuffered<pbtest::PackedRepeatedFields> msg;
Primiano Tucci03ac8332019-11-06 13:30:36 +0000510 PackedFixedSizeInt<uint32_t> buf;
Ryancbd16152019-09-04 16:54:45 +0100511 buf.Append(1);
512 buf.Append(2);
513 buf.Append(3);
514 const uint8_t* data = buf.data();
515 size_t size = buf.size();
516 size_t invalid_size = size - 2;
517 constexpr int kFieldId =
518 pbtest::PackedRepeatedFields::kFieldFixed32FieldNumber;
519 msg->AppendBytes(kFieldId, data, invalid_size);
520 std::string serialized = msg.SerializeAsString();
521
522 // Iterator indicates parse error.
523 auto decoder = pbtest::PackedRepeatedFields::Decoder(serialized);
524 ASSERT_TRUE(decoder.has_field_fixed32());
525 bool parse_error = false;
526 for (auto packed_it = decoder.field_fixed32(&parse_error); packed_it;
527 packed_it++) {
528 }
529 ASSERT_TRUE(parse_error);
530}
531
532TEST(ProtoDecoderTest, MalformedPackedVarIntBuffer) {
533 // Encode a varint field with the last varint chopped off partway.
534 HeapBuffered<pbtest::PackedRepeatedFields> msg;
Primiano Tucci03ac8332019-11-06 13:30:36 +0000535 PackedVarInt buf;
Ryancbd16152019-09-04 16:54:45 +0100536 buf.Append(1024);
537 buf.Append(2048);
538 buf.Append(4096);
539 const uint8_t* data = buf.data();
540 size_t size = buf.size();
541 size_t invalid_size = size - 1;
542 constexpr int kFieldId = pbtest::PackedRepeatedFields::kFieldInt32FieldNumber;
543 msg->AppendBytes(kFieldId, data, invalid_size);
544 std::string serialized = msg.SerializeAsString();
545
546 // Iterator indicates parse error.
547 auto decoder = pbtest::PackedRepeatedFields::Decoder(serialized);
548 ASSERT_TRUE(decoder.has_field_int32());
549 bool parse_error = false;
550 for (auto packed_it = decoder.field_int32(&parse_error); packed_it;
551 packed_it++) {
552 }
553 ASSERT_TRUE(parse_error);
554}
555
Primiano Tucci2cfc7fd2019-11-28 16:07:27 +0000556// Tests that big field ids (> 0xffff) are just skipped but don't fail parsing.
557// This is a regression test for b/145339282 (DataSourceConfig.for_testing
558// having a very large ID == 268435455 until Android R).
559TEST(ProtoDecoderTest, SkipBigFieldIds) {
560 Message message;
561 ScatteredHeapBuffer delegate(512, 512);
562 ScatteredStreamWriter writer(&delegate);
563 delegate.set_writer(&writer);
564 message.Reset(&writer);
565 message.AppendVarInt(/*field_id=*/1, 11);
566 message.AppendVarInt(/*field_id=*/1000000, 0); // Will be skipped
567 message.AppendVarInt(/*field_id=*/65535, 99);
568 message.AppendVarInt(/*field_id=*/268435455, 0); // Will be skipped
569 message.AppendVarInt(/*field_id=*/2, 12);
570 message.AppendVarInt(/*field_id=*/2000000, 0); // Will be skipped
571 std::vector<uint8_t> data = delegate.StitchSlices();
572
573 // Check the iterator-based ProtoDecoder.
574 {
575 ProtoDecoder decoder(data.data(), data.size());
576 Field field = decoder.ReadField();
577 ASSERT_TRUE(field.valid());
578 ASSERT_EQ(field.id(), 1u);
579 ASSERT_EQ(field.as_int32(), 11);
580
581 field = decoder.ReadField();
582 ASSERT_TRUE(field.valid());
583 ASSERT_EQ(field.id(), 65535u);
584 ASSERT_EQ(field.as_int32(), 99);
585
586 field = decoder.ReadField();
587 ASSERT_TRUE(field.valid());
588 ASSERT_EQ(field.id(), 2u);
589 ASSERT_EQ(field.as_int32(), 12);
590
591 field = decoder.ReadField();
592 ASSERT_FALSE(field.valid());
593 }
594
595 // Test the one-shot-read TypedProtoDecoder.
596 // Note: field 65535 will be also skipped because this TypedProtoDecoder has
597 // a cap on MAX_FIELD_ID = 3.
598 {
599 TypedProtoDecoder<3, true> tpd(data.data(), data.size());
600 EXPECT_EQ(tpd.Get(1).as_int32(), 11);
601 EXPECT_EQ(tpd.Get(2).as_int32(), 12);
602 }
603}
604
605// Edge case for SkipBigFieldIds, the message contains only one field with a
606// very big id. Test that we skip it and return an invalid field, instead of
607// geetting stuck in some loop.
608TEST(ProtoDecoderTest, OneBigFieldIdOnly) {
609 Message message;
610 ScatteredHeapBuffer delegate(512, 512);
611 ScatteredStreamWriter writer(&delegate);
612 delegate.set_writer(&writer);
613 message.Reset(&writer);
614 message.AppendVarInt(/*field_id=*/268435455, 0);
615 std::vector<uint8_t> data = delegate.StitchSlices();
616
617 // Check the iterator-based ProtoDecoder.
618 ProtoDecoder decoder(data.data(), data.size());
619 Field field = decoder.ReadField();
620 ASSERT_FALSE(field.valid());
621}
622
Lalit Maganti45172a82018-06-01 03:04:43 +0100623} // namespace
624} // namespace protozero