1 /*
2 * Copyright (C) 2018 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 #include "perfetto/protozero/proto_decoder.h"
18
19 #include "perfetto/ext/base/utils.h"
20 #include "perfetto/protozero/message.h"
21 #include "perfetto/protozero/proto_utils.h"
22 #include "perfetto/protozero/scattered_heap_buffer.h"
23 #include "perfetto/protozero/static_buffer.h"
24 #include "test/gtest_and_gmock.h"
25
26 #include "src/protozero/test/example_proto/test_messages.pb.h"
27 #include "src/protozero/test/example_proto/test_messages.pbzero.h"
28
29 // Generated by the protozero plugin.
30 namespace pbtest = protozero::test::protos::pbzero;
31
32 // Generated by the official protobuf compiler.
33 namespace pbgold = protozero::test::protos;
34
35 namespace protozero {
36 namespace {
37
38 using ::testing::_;
39 using ::testing::ElementsAre;
40 using ::testing::InSequence;
41 using ::testing::Invoke;
42 using namespace proto_utils;
43
TEST(ProtoDecoderTest,ReadString)44 TEST(ProtoDecoderTest, ReadString) {
45 HeapBuffered<Message> message;
46
47 static constexpr char kTestString[] = "test";
48 message->AppendString(1, kTestString);
49 std::vector<uint8_t> proto = message.SerializeAsArray();
50 TypedProtoDecoder<32, false> decoder(proto.data(), proto.size());
51
52 const auto& field = decoder.Get(1);
53 ASSERT_EQ(field.type(), ProtoWireType::kLengthDelimited);
54 ASSERT_EQ(field.size(), sizeof(kTestString) - 1);
55 for (size_t i = 0; i < sizeof(kTestString) - 1; i++) {
56 ASSERT_EQ(field.data()[i], kTestString[i]);
57 }
58 }
59
TEST(ProtoDecoderTest,SkipVeryLargeFields)60 TEST(ProtoDecoderTest, SkipVeryLargeFields) {
61 const size_t kPayloadSize = 257 * 1024 * 1024;
62 const uint64_t data_size = 4096 + kPayloadSize;
63 std::unique_ptr<uint8_t, perfetto::base::FreeDeleter> data(
64 static_cast<uint8_t*>(malloc(data_size)));
65 StaticBuffered<Message> message(data.get(), data_size);
66
67 // Append a valid field.
68 message->AppendVarInt(/*field_id=*/1, 11);
69
70 // Append a very large field that will be skipped.
71 uint8_t raw[10];
72 uint8_t* wptr = raw;
73 wptr = WriteVarInt(MakeTagLengthDelimited(2), wptr);
74 wptr = WriteVarInt(kPayloadSize, wptr);
75 message->AppendRawProtoBytes(raw, static_cast<size_t>(wptr - raw));
76 const size_t kPaddingSize = 1024 * 128;
77 std::unique_ptr<uint8_t[]> padding(new uint8_t[kPaddingSize]());
78 for (size_t i = 0; i < kPayloadSize / kPaddingSize; i++)
79 message->AppendRawProtoBytes(padding.get(), kPaddingSize);
80
81 // Append another valid field.
82 message->AppendVarInt(/*field_id=*/3, 13);
83
84 ProtoDecoder decoder(data.get(), message.Finalize());
85 Field field = decoder.ReadField();
86 ASSERT_EQ(1u, field.id());
87 ASSERT_EQ(11, field.as_int32());
88
89 field = decoder.ReadField();
90 ASSERT_EQ(3u, field.id());
91 ASSERT_EQ(13, field.as_int32());
92
93 field = decoder.ReadField();
94 ASSERT_FALSE(field.valid());
95 }
96
TEST(ProtoDecoderTest,SingleRepeatedField)97 TEST(ProtoDecoderTest, SingleRepeatedField) {
98 HeapBuffered<Message> message;
99 message->AppendVarInt(/*field_id=*/2, 10);
100 auto data = message.SerializeAsArray();
101 TypedProtoDecoder<2, true> tpd(data.data(), data.size());
102 auto it = tpd.GetRepeated<int32_t>(/*field_id=*/2);
103 EXPECT_TRUE(it);
104 EXPECT_EQ(it.field().as_int32(), 10);
105 EXPECT_EQ(*it, 10);
106 EXPECT_FALSE(++it);
107 }
108
TEST(ProtoDecoderTest,RepeatedVariableLengthField)109 TEST(ProtoDecoderTest, RepeatedVariableLengthField) {
110 HeapBuffered<Message> message;
111
112 static constexpr char kTestString[] = "test";
113 static constexpr char kTestString2[] = "honk honk";
114 message->AppendString(1, kTestString);
115 message->AppendString(1, kTestString2);
116 std::vector<uint8_t> proto = message.SerializeAsArray();
117 TypedProtoDecoder<32, false> decoder(proto.data(), proto.size());
118
119 auto it = decoder.GetRepeated<ConstChars>(1);
120 ASSERT_EQ(it->type(), ProtoWireType::kLengthDelimited);
121 ASSERT_EQ(it->size(), sizeof(kTestString) - 1);
122 ASSERT_EQ(it->as_std_string(), std::string(kTestString));
123 ASSERT_EQ((*it).ToStdString(), std::string(kTestString));
124 ++it;
125 ASSERT_EQ(it->type(), ProtoWireType::kLengthDelimited);
126 ASSERT_EQ(it->size(), sizeof(kTestString2) - 1);
127 ASSERT_EQ(it->as_std_string(), std::string(kTestString2));
128 ASSERT_EQ((*it).ToStdString(), std::string(kTestString2));
129 }
130
TEST(ProtoDecoderTest,SingleRepeatedFieldWithExpansion)131 TEST(ProtoDecoderTest, SingleRepeatedFieldWithExpansion) {
132 HeapBuffered<Message> message;
133 for (int i = 0; i < 2000; i++) {
134 message->AppendVarInt(/*field_id=*/2, i);
135 }
136 auto data = message.SerializeAsArray();
137 TypedProtoDecoder<2, true> tpd(data.data(), data.size());
138 auto it = tpd.GetRepeated<int32_t>(/*field_id=*/2);
139 for (int i = 0; i < 2000; i++) {
140 EXPECT_TRUE(it);
141 EXPECT_EQ(*it, i);
142 ++it;
143 }
144 EXPECT_FALSE(it);
145 }
146
TEST(ProtoDecoderTest,NoRepeatedField)147 TEST(ProtoDecoderTest, NoRepeatedField) {
148 uint8_t buf[] = {0x01};
149 TypedProtoDecoder<2, true> tpd(buf, 1);
150 auto it = tpd.GetRepeated<int32_t>(/*field_id=*/1);
151 EXPECT_FALSE(it);
152 EXPECT_FALSE(tpd.Get(2).valid());
153 }
154
TEST(ProtoDecoderTest,RepeatedFields)155 TEST(ProtoDecoderTest, RepeatedFields) {
156 HeapBuffered<Message> message;
157
158 message->AppendVarInt(1, 10);
159 message->AppendVarInt(2, 20);
160 message->AppendVarInt(3, 30);
161
162 message->AppendVarInt(1, 11);
163 message->AppendVarInt(2, 21);
164 message->AppendVarInt(2, 22);
165
166 // When iterating with the simple decoder we should just see fields in parsing
167 // order.
168 auto data = message.SerializeAsArray();
169 ProtoDecoder decoder(data.data(), data.size());
170 std::string fields_seen;
171 for (auto fld = decoder.ReadField(); fld.valid(); fld = decoder.ReadField()) {
172 fields_seen +=
173 std::to_string(fld.id()) + ":" + std::to_string(fld.as_int32()) + ";";
174 }
175 EXPECT_EQ(fields_seen, "1:10;2:20;3:30;1:11;2:21;2:22;");
176
177 TypedProtoDecoder<4, true> tpd(data.data(), data.size());
178
179 // When parsing with the one-shot decoder and querying the single field id, we
180 // should see the last value for each of them, not the first one. This is the
181 // current behavior of Google protobuf's parser.
182 EXPECT_EQ(tpd.Get(1).as_int32(), 11);
183 EXPECT_EQ(tpd.Get(2).as_int32(), 22);
184 EXPECT_EQ(tpd.Get(3).as_int32(), 30);
185
186 // But when iterating we should see values in the original order.
187 auto it = tpd.GetRepeated<int32_t>(1);
188 EXPECT_EQ(*it, 10);
189 EXPECT_EQ(*++it, 11);
190 EXPECT_FALSE(++it);
191
192 it = tpd.GetRepeated<int32_t>(2);
193 EXPECT_EQ(*it++, 20);
194 EXPECT_EQ(*it++, 21);
195 EXPECT_EQ(*it++, 22);
196 EXPECT_FALSE(it);
197
198 it = tpd.GetRepeated<int32_t>(3);
199 EXPECT_EQ(*it, 30);
200 EXPECT_FALSE(++it);
201 }
202
TEST(ProtoDecoderTest,FixedData)203 TEST(ProtoDecoderTest, FixedData) {
204 struct FieldExpectation {
205 const char* encoded;
206 size_t encoded_size;
207 uint32_t id;
208 ProtoWireType type;
209 uint64_t int_value;
210 };
211
212 const FieldExpectation kFieldExpectations[] = {
213 {"\x08\x00", 2, 1, ProtoWireType::kVarInt, 0},
214 {"\x08\x01", 2, 1, ProtoWireType::kVarInt, 1},
215 {"\x08\x42", 2, 1, ProtoWireType::kVarInt, 0x42},
216 {"\xF8\x07\x42", 3, 127, ProtoWireType::kVarInt, 0x42},
217 {"\xB8\x3E\xFF\xFF\xFF\xFF\x0F", 7, 999, ProtoWireType::kVarInt,
218 0xFFFFFFFF},
219 {"\x7D\x42\x00\x00\x00", 5, 15, ProtoWireType::kFixed32, 0x42},
220 {"\xBD\x3E\x78\x56\x34\x12", 6, 999, ProtoWireType::kFixed32, 0x12345678},
221 {"\x79\x42\x00\x00\x00\x00\x00\x00\x00", 9, 15, ProtoWireType::kFixed64,
222 0x42},
223 {"\xB9\x3E\x08\x07\x06\x05\x04\x03\x02\x01", 10, 999,
224 ProtoWireType::kFixed64, 0x0102030405060708},
225 {"\x0A\x00", 2, 1, ProtoWireType::kLengthDelimited, 0},
226 {"\x0A\x04|abc", 6, 1, ProtoWireType::kLengthDelimited, 4},
227 {"\xBA\x3E\x04|abc", 7, 999, ProtoWireType::kLengthDelimited, 4},
228 {"\xBA\x3E\x83\x01|abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzab"
229 "cdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu"
230 "vwx",
231 135, 999, ProtoWireType::kLengthDelimited, 131},
232 };
233
234 for (size_t i = 0; i < perfetto::base::ArraySize(kFieldExpectations); ++i) {
235 const FieldExpectation& exp = kFieldExpectations[i];
236 TypedProtoDecoder<999, 0> decoder(
237 reinterpret_cast<const uint8_t*>(exp.encoded), exp.encoded_size);
238
239 auto& field = decoder.Get(exp.id);
240 ASSERT_EQ(exp.type, field.type());
241
242 if (field.type() == ProtoWireType::kLengthDelimited) {
243 ASSERT_EQ(exp.int_value, field.size());
244 } else {
245 ASSERT_EQ(int64_t(exp.int_value), field.as_int64());
246 // Proto encodes booleans as varints of 0 or 1.
247 if (exp.int_value == 0 || exp.int_value == 1) {
248 ASSERT_EQ(int64_t(exp.int_value), field.as_bool());
249 }
250 }
251 }
252
253 // Test float and doubles decoding.
254 const char buf[] = "\x0d\x00\x00\xa0\x3f\x11\x00\x00\x00\x00\x00\x42\x8f\xc0";
255 TypedProtoDecoder<2, false> decoder(reinterpret_cast<const uint8_t*>(buf),
256 sizeof(buf));
257 EXPECT_FLOAT_EQ(decoder.Get(1).as_float(), 1.25f);
258 EXPECT_DOUBLE_EQ(decoder.Get(2).as_double(), -1000.25);
259 }
260
TEST(ProtoDecoderTest,FindField)261 TEST(ProtoDecoderTest, FindField) {
262 uint8_t buf[] = {0x08, 0x00}; // field_id 1, varint value 0.
263 ProtoDecoder pd(buf, 2);
264
265 auto field = pd.FindField(1);
266 ASSERT_TRUE(field);
267 EXPECT_EQ(field.as_int64(), 0);
268
269 auto field2 = pd.FindField(2);
270 EXPECT_FALSE(field2);
271 }
272
TEST(ProtoDecoderTest,MoveTypedDecoder)273 TEST(ProtoDecoderTest, MoveTypedDecoder) {
274 HeapBuffered<Message> message;
275 message->AppendVarInt(/*field_id=*/1, 10);
276 std::vector<uint8_t> proto = message.SerializeAsArray();
277
278 // Construct a decoder that uses inline storage (i.e., the fields are stored
279 // within the object itself).
280 using Decoder = TypedProtoDecoder<32, false>;
281 std::unique_ptr<Decoder> decoder(new Decoder(proto.data(), proto.size()));
282 ASSERT_GE(reinterpret_cast<uintptr_t>(&decoder->at<1>()),
283 reinterpret_cast<uintptr_t>(decoder.get()));
284 ASSERT_LT(reinterpret_cast<uintptr_t>(&decoder->at<1>()),
285 reinterpret_cast<uintptr_t>(decoder.get()) + sizeof(Decoder));
286
287 // Move the decoder into another object and deallocate the original object.
288 Decoder decoder2(std::move(*decoder));
289 decoder.reset();
290
291 // Check that the contents got moved correctly.
292 EXPECT_EQ(decoder2.Get(1).as_int32(), 10);
293 ASSERT_GE(reinterpret_cast<uintptr_t>(&decoder2.at<1>()),
294 reinterpret_cast<uintptr_t>(&decoder2));
295 ASSERT_LT(reinterpret_cast<uintptr_t>(&decoder2.at<1>()),
296 reinterpret_cast<uintptr_t>(&decoder2) + sizeof(Decoder));
297 }
298
TEST(ProtoDecoderTest,PackedRepeatedVarint)299 TEST(ProtoDecoderTest, PackedRepeatedVarint) {
300 std::vector<int32_t> values = {42, 255, 0, -1};
301
302 // serialize using protobuf library
303 pbgold::PackedRepeatedFields msg;
304 for (auto v : values)
305 msg.add_field_int32(v);
306 std::string serialized = msg.SerializeAsString();
307
308 // decode using TypedProtoDecoder directly
309 {
310 constexpr int kFieldId =
311 pbtest::PackedRepeatedFields::kFieldInt32FieldNumber;
312 TypedProtoDecoder<kFieldId, false> decoder(
313 reinterpret_cast<const uint8_t*>(serialized.data()), serialized.size());
314 ASSERT_TRUE(decoder.at<kFieldId>().valid());
315 bool parse_error = false;
316 auto packed_it =
317 decoder.GetPackedRepeated<proto_utils::ProtoWireType::kVarInt, int32_t>(
318 kFieldId, &parse_error);
319
320 std::vector<int32_t> decoded_values;
321 for (; packed_it; ++packed_it) {
322 auto v = *packed_it;
323 decoded_values.push_back(v);
324 }
325 ASSERT_EQ(values, decoded_values);
326 ASSERT_FALSE(parse_error);
327 }
328
329 // decode using plugin-generated accessor
330 {
331 auto decoder = pbtest::PackedRepeatedFields::Decoder(serialized);
332 ASSERT_TRUE(decoder.has_field_int32());
333
334 bool parse_error = false;
335 std::vector<int32_t> decoded_values;
336 for (auto packed_it = decoder.field_int32(&parse_error); packed_it;
337 ++packed_it) {
338 auto v = *packed_it;
339 decoded_values.push_back(v);
340 }
341 ASSERT_EQ(values, decoded_values);
342 ASSERT_FALSE(parse_error);
343 }
344
345 // unset field case
346 pbgold::PackedRepeatedFields empty_msg;
347 std::string empty_serialized = empty_msg.SerializeAsString();
348 auto decoder = pbtest::PackedRepeatedFields::Decoder(empty_serialized);
349 ASSERT_FALSE(decoder.has_field_int32());
350 bool parse_error = false;
351 auto packed_it = decoder.field_int32(&parse_error);
352 ASSERT_FALSE(bool(packed_it));
353 ASSERT_FALSE(parse_error);
354 }
355
TEST(ProtoDecoderTest,PackedRepeatedFixed32)356 TEST(ProtoDecoderTest, PackedRepeatedFixed32) {
357 std::vector<uint32_t> values = {42, 255, 0, 1};
358
359 // serialize using protobuf library
360 pbgold::PackedRepeatedFields msg;
361 for (auto v : values)
362 msg.add_field_fixed32(v);
363 std::string serialized = msg.SerializeAsString();
364
365 // decode using TypedProtoDecoder directly
366 {
367 constexpr int kFieldId =
368 pbtest::PackedRepeatedFields::kFieldFixed32FieldNumber;
369 TypedProtoDecoder<kFieldId, false> decoder(
370 reinterpret_cast<const uint8_t*>(serialized.data()), serialized.size());
371 bool parse_error = false;
372 auto packed_it =
373 decoder
374 .GetPackedRepeated<proto_utils::ProtoWireType::kFixed32, uint32_t>(
375 kFieldId, &parse_error);
376
377 std::vector<uint32_t> decoded_values;
378 for (; packed_it; ++packed_it) {
379 auto v = *packed_it;
380 decoded_values.push_back(v);
381 }
382 ASSERT_EQ(values, decoded_values);
383 ASSERT_FALSE(parse_error);
384 }
385
386 // decode using plugin-generated accessor
387 {
388 auto decoder = pbtest::PackedRepeatedFields::Decoder(serialized);
389 ASSERT_TRUE(decoder.has_field_fixed32());
390
391 bool parse_error = false;
392 std::vector<uint32_t> decoded_values;
393 for (auto packed_it = decoder.field_fixed32(&parse_error); packed_it;
394 packed_it++) {
395 auto v = *packed_it;
396 decoded_values.push_back(v);
397 }
398 ASSERT_EQ(values, decoded_values);
399 ASSERT_FALSE(parse_error);
400 }
401
402 // unset field case
403 pbgold::PackedRepeatedFields empty_msg;
404 std::string empty_serialized = empty_msg.SerializeAsString();
405 auto decoder = pbtest::PackedRepeatedFields::Decoder(empty_serialized);
406 ASSERT_FALSE(decoder.has_field_fixed32());
407 bool parse_error = false;
408 auto packed_it = decoder.field_fixed32(&parse_error);
409 ASSERT_FALSE(bool(packed_it));
410 ASSERT_FALSE(parse_error);
411 }
412
TEST(ProtoDecoderTest,PackedRepeatedFixed64)413 TEST(ProtoDecoderTest, PackedRepeatedFixed64) {
414 std::vector<int64_t> values = {42, 255, 0, -1};
415
416 // serialize using protobuf library
417 pbgold::PackedRepeatedFields msg;
418 for (auto v : values)
419 msg.add_field_sfixed64(v);
420 std::string serialized = msg.SerializeAsString();
421
422 // decode using TypedProtoDecoder directly
423 {
424 constexpr int kFieldId =
425 pbtest::PackedRepeatedFields::kFieldSfixed64FieldNumber;
426 TypedProtoDecoder<kFieldId, false> decoder(
427 reinterpret_cast<const uint8_t*>(serialized.data()), serialized.size());
428 bool parse_error = false;
429 auto packed_it =
430 decoder
431 .GetPackedRepeated<proto_utils::ProtoWireType::kFixed64, int64_t>(
432 kFieldId, &parse_error);
433
434 std::vector<int64_t> decoded_values;
435 for (; packed_it; ++packed_it) {
436 auto v = *packed_it;
437 decoded_values.push_back(v);
438 }
439 ASSERT_EQ(values, decoded_values);
440 ASSERT_FALSE(parse_error);
441 }
442
443 // decode using plugin-generated accessor
444 {
445 auto decoder = pbtest::PackedRepeatedFields::Decoder(serialized);
446 ASSERT_TRUE(decoder.has_field_sfixed64());
447
448 bool parse_error = false;
449 std::vector<int64_t> decoded_values;
450 for (auto packed_it = decoder.field_sfixed64(&parse_error); packed_it;
451 packed_it++) {
452 auto v = *packed_it;
453 decoded_values.push_back(v);
454 }
455 ASSERT_EQ(values, decoded_values);
456 ASSERT_FALSE(parse_error);
457 }
458
459 // unset field case
460 pbgold::PackedRepeatedFields empty_msg;
461 std::string empty_serialized = empty_msg.SerializeAsString();
462 auto decoder = pbtest::PackedRepeatedFields::Decoder(empty_serialized);
463 ASSERT_FALSE(decoder.has_field_sfixed64());
464 bool parse_error = false;
465 auto packed_it = decoder.field_sfixed64(&parse_error);
466 ASSERT_FALSE(bool(packed_it));
467 ASSERT_FALSE(parse_error);
468 }
469
TEST(ProtoDecoderTest,ZeroLengthPackedRepeatedField)470 TEST(ProtoDecoderTest, ZeroLengthPackedRepeatedField) {
471 HeapBuffered<pbtest::PackedRepeatedFields> msg;
472 PackedVarInt buf;
473 msg->set_field_int32(buf);
474 std::string serialized = msg.SerializeAsString();
475
476 // Encoded as 2 bytes: tag/field, and a length of zero.
477 EXPECT_EQ(2u, serialized.size());
478
479 // Appears empty when decoded.
480 auto decoder = pbtest::PackedRepeatedFields::Decoder(serialized);
481 ASSERT_TRUE(decoder.has_field_int32());
482 bool parse_error = false;
483 auto packed_it = decoder.field_int32(&parse_error);
484 ASSERT_FALSE(bool(packed_it));
485 ASSERT_FALSE(parse_error);
486 }
487
TEST(ProtoDecoderTest,MalformedPackedFixedBuffer)488 TEST(ProtoDecoderTest, MalformedPackedFixedBuffer) {
489 // Encode a fixed32 field where the length is not a multiple of 4 bytes.
490 HeapBuffered<pbtest::PackedRepeatedFields> msg;
491 PackedFixedSizeInt<uint32_t> buf;
492 buf.Append(1);
493 buf.Append(2);
494 buf.Append(3);
495 const uint8_t* data = buf.data();
496 size_t size = buf.size();
497 size_t invalid_size = size - 2;
498 constexpr int kFieldId =
499 pbtest::PackedRepeatedFields::kFieldFixed32FieldNumber;
500 msg->AppendBytes(kFieldId, data, invalid_size);
501 std::string serialized = msg.SerializeAsString();
502
503 // Iterator indicates parse error.
504 auto decoder = pbtest::PackedRepeatedFields::Decoder(serialized);
505 ASSERT_TRUE(decoder.has_field_fixed32());
506 bool parse_error = false;
507 for (auto packed_it = decoder.field_fixed32(&parse_error); packed_it;
508 packed_it++) {
509 }
510 ASSERT_TRUE(parse_error);
511 }
512
TEST(ProtoDecoderTest,MalformedPackedVarIntBuffer)513 TEST(ProtoDecoderTest, MalformedPackedVarIntBuffer) {
514 // Encode a varint field with the last varint chopped off partway.
515 HeapBuffered<pbtest::PackedRepeatedFields> msg;
516 PackedVarInt buf;
517 buf.Append(1024);
518 buf.Append(2048);
519 buf.Append(4096);
520 const uint8_t* data = buf.data();
521 size_t size = buf.size();
522 size_t invalid_size = size - 1;
523 constexpr int kFieldId = pbtest::PackedRepeatedFields::kFieldInt32FieldNumber;
524 msg->AppendBytes(kFieldId, data, invalid_size);
525 std::string serialized = msg.SerializeAsString();
526
527 // Iterator indicates parse error.
528 auto decoder = pbtest::PackedRepeatedFields::Decoder(serialized);
529 ASSERT_TRUE(decoder.has_field_int32());
530 bool parse_error = false;
531 for (auto packed_it = decoder.field_int32(&parse_error); packed_it;
532 packed_it++) {
533 }
534 ASSERT_TRUE(parse_error);
535 }
536
537 // Tests that:
538 // 1. Very big field ids (>= 2**24) are just skipped but don't fail parsing.
539 // This is a regression test for b/145339282 (DataSourceConfig.for_testing
540 // having a very large ID == 268435455 until Android R).
541 // 2. Moderately big" field ids can be parsed correctly. See also
542 // https://github.com/google/perfetto/issues/510 .
TEST(ProtoDecoderTest,BigFieldIds)543 TEST(ProtoDecoderTest, BigFieldIds) {
544 HeapBuffered<Message> message;
545 message->AppendVarInt(/*field_id=*/1, 11);
546 message->AppendVarInt(/*field_id=*/1 << 24, 0); // Will be skipped
547 message->AppendVarInt(/*field_id=*/65535, 99);
548 message->AppendVarInt(/*field_id=*/(1 << 24) + 1023,
549 0); // Will be skipped
550 message->AppendVarInt(/*field_id=*/2, 12);
551 message->AppendVarInt(/*field_id=*/1 << 28, 0); // Will be skipped
552
553 message->AppendVarInt(/*field_id=*/(1 << 24) - 1, 13);
554 auto data = message.SerializeAsArray();
555
556 // Check the iterator-based ProtoDecoder.
557 {
558 ProtoDecoder decoder(data.data(), data.size());
559 Field field = decoder.ReadField();
560 ASSERT_TRUE(field.valid());
561 ASSERT_EQ(field.id(), 1u);
562 ASSERT_EQ(field.as_int32(), 11);
563
564 field = decoder.ReadField();
565 ASSERT_TRUE(field.valid());
566 ASSERT_EQ(field.id(), 65535u);
567 ASSERT_EQ(field.as_int32(), 99);
568
569 field = decoder.ReadField();
570 ASSERT_TRUE(field.valid());
571 ASSERT_EQ(field.id(), 2u);
572 ASSERT_EQ(field.as_int32(), 12);
573
574 field = decoder.ReadField();
575 ASSERT_TRUE(field.valid());
576 ASSERT_EQ(field.id(), (1u << 24) - 1u);
577 ASSERT_EQ(field.as_int32(), 13);
578
579 field = decoder.ReadField();
580 ASSERT_FALSE(field.valid());
581 }
582
583 // Test the one-shot-read TypedProtoDecoder.
584 // Note: field 65535 will be also skipped because this TypedProtoDecoder has
585 // a cap on MAX_FIELD_ID = 3.
586 {
587 TypedProtoDecoder<3, true> tpd(data.data(), data.size());
588 EXPECT_EQ(tpd.Get(1).as_int32(), 11);
589 EXPECT_EQ(tpd.Get(2).as_int32(), 12);
590 }
591 }
592
593 // Edge case for SkipBigFieldIds, the message contains only one field with a
594 // very big id. Test that we skip it and return an invalid field, instead of
595 // geetting stuck in some loop.
TEST(ProtoDecoderTest,OneBigFieldIdOnly)596 TEST(ProtoDecoderTest, OneBigFieldIdOnly) {
597 HeapBuffered<Message> message;
598 message->AppendVarInt(/*field_id=*/268435455, 0);
599 auto data = message.SerializeAsArray();
600
601 // Check the iterator-based ProtoDecoder.
602 ProtoDecoder decoder(data.data(), data.size());
603 Field field = decoder.ReadField();
604 ASSERT_FALSE(field.valid());
605 }
606
607 // Check what happens when trying to parse packed repeated field and finding a
608 // mismatching wire type instead. A compliant protobuf decoder should accept it,
609 // but protozero doesn't handle that. At least it shouldn't crash.
TEST(ProtoDecoderTest,PacketRepeatedWireTypeMismatch)610 TEST(ProtoDecoderTest, PacketRepeatedWireTypeMismatch) {
611 protozero::HeapBuffered<pbtest::PackedRepeatedFields> message;
612 // A proper packed encoding should have a length delimited wire type. Use a
613 // var int wire type instead.
614 constexpr int kFieldId = pbtest::PackedRepeatedFields::kFieldInt32FieldNumber;
615 message->AppendTinyVarInt(kFieldId, 5);
616 auto data = message.SerializeAsArray();
617
618 pbtest::PackedRepeatedFields::Decoder decoder(data.data(), data.size());
619 bool parse_error = false;
620 auto it = decoder.field_int32(&parse_error);
621 // The decoder doesn't return a parse error (maybe it should, but that has
622 // been the behavior since the beginning).
623 ASSERT_FALSE(parse_error);
624 // But the iterator returns 0 elements.
625 EXPECT_FALSE(it);
626 }
627
TEST(ProtoDecoderTest,RepeatedMaxFieldIdStack)628 TEST(ProtoDecoderTest, RepeatedMaxFieldIdStack) {
629 HeapBuffered<Message> message;
630 message->AppendVarInt(15, 1);
631 message->AppendVarInt(15, 2);
632 std::vector<uint8_t> proto = message.SerializeAsArray();
633
634 // Make sure that even with a max field id close to the stack capacity,
635 // TypedProtoDecoder behaves correctly w.r.t. repeated fields.
636 const int kMaxFieldId = PROTOZERO_DECODER_INITIAL_STACK_CAPACITY;
637
638 {
639 protozero::TypedProtoDecoder<kMaxFieldId,
640 /*HAS_NONPACKED_REPEATED_FIELDS=*/true>
641 decoder(proto.data(), proto.size());
642 std::vector<uint64_t> res;
643 for (auto it = decoder.GetRepeated<uint64_t>(15); it; it++) {
644 res.push_back(*it);
645 }
646 EXPECT_THAT(res, ElementsAre(1, 2));
647 }
648 }
649
650 } // namespace
651 } // namespace protozero
652