xref: /aosp_15_r20/external/perfetto/src/protozero/message_unittest.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2017 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/message.h"
18 
19 #include <limits>
20 #include <memory>
21 #include <utility>
22 #include <vector>
23 
24 #include "perfetto/base/logging.h"
25 #include "perfetto/protozero/message_handle.h"
26 #include "perfetto/protozero/proto_utils.h"
27 #include "perfetto/protozero/root_message.h"
28 #include "src/base/test/utils.h"
29 #include "src/protozero/test/fake_scattered_buffer.h"
30 #include "test/gtest_and_gmock.h"
31 
32 namespace protozero {
33 
34 namespace {
35 
36 constexpr size_t kChunkSize = 16;
37 constexpr uint8_t kTestBytes[] = {0, 0, 0, 0, 0x42, 1, 0x42, 0xff, 0x42, 0};
38 constexpr const char kStartWatermark[] = {'a', 'b', 'c', 'd',
39                                           '1', '2', '3', '\0'};
40 constexpr const char kEndWatermark[] = {'9', '8', '7', '6',
41                                         'z', 'w', 'y', '\0'};
42 
43 class FakeRootMessage : public RootMessage<Message> {};
44 class FakeChildMessage : public Message {};
45 
SimpleHash(const std::string & str)46 uint32_t SimpleHash(const std::string& str) {
47   uint32_t hash = 5381;
48   for (char c : str)
49     hash = 33 * hash + static_cast<uint32_t>(c);
50   return hash;
51 }
52 
53 class MessageTest : public ::testing::Test {
54  public:
SetUp()55   void SetUp() override { SetChunkSize(kChunkSize); }
56 
TearDown()57   void TearDown() override {
58     // Check that none of the messages created by the text fixtures below did
59     // under/overflow their heap boundaries.
60     for (std::unique_ptr<uint8_t[]>& mem : messages_) {
61       EXPECT_STREQ(kStartWatermark, reinterpret_cast<char*>(mem.get()));
62       EXPECT_STREQ(kEndWatermark,
63                    reinterpret_cast<char*>(mem.get() + sizeof(kStartWatermark) +
64                                            sizeof(FakeRootMessage)));
65       FakeRootMessage* msg = reinterpret_cast<FakeRootMessage*>(
66           mem.get() + sizeof(kStartWatermark));
67       msg->~FakeRootMessage();
68       mem.reset();
69     }
70     messages_.clear();
71     stream_writer_.reset();
72     buffer_.reset();
73   }
74 
ResetMessage(FakeRootMessage * msg)75   void ResetMessage(FakeRootMessage* msg) { msg->Reset(stream_writer_.get()); }
76 
SetChunkSize(size_t size)77   void SetChunkSize(size_t size) {
78     buffer_.reset(new FakeScatteredBuffer(size));
79     stream_writer_.reset(new ScatteredStreamWriter(buffer_.get()));
80     chunk_size_ = size;
81     readback_pos_ = 0;
82   }
83 
NewMessage()84   FakeRootMessage* NewMessage() {
85     std::unique_ptr<uint8_t[]> mem(
86         new uint8_t[sizeof(kStartWatermark) + sizeof(FakeRootMessage) +
87                     sizeof(kEndWatermark)]);
88     uint8_t* msg_start = mem.get() + sizeof(kStartWatermark);
89     memcpy(mem.get(), kStartWatermark, sizeof(kStartWatermark));
90     memset(msg_start, 0, sizeof(FakeRootMessage));
91     memcpy(msg_start + sizeof(FakeRootMessage), kEndWatermark,
92            sizeof(kEndWatermark));
93     messages_.push_back(std::move(mem));
94     FakeRootMessage* msg = new (msg_start) FakeRootMessage();
95     msg->Reset(stream_writer_.get());
96     return msg;
97   }
98 
NewMessageWithSizeField()99   FakeRootMessage* NewMessageWithSizeField() {
100     FakeRootMessage* msg = NewMessage();
101     uint8_t* size_field =
102         stream_writer_->ReserveBytes(proto_utils::kMessageLengthFieldSize);
103     memset(size_field, 0u, proto_utils::kMessageLengthFieldSize);
104     msg->set_size_field(size_field);
105     return msg;
106   }
107 
GetNumSerializedBytes()108   size_t GetNumSerializedBytes() {
109     if (buffer_->chunks().empty())
110       return 0;
111     return buffer_->chunks().size() * chunk_size_ -
112            stream_writer_->bytes_available();
113   }
114 
GetNextSerializedBytes(size_t num_bytes)115   std::string GetNextSerializedBytes(size_t num_bytes) {
116     size_t old_readback_pos = readback_pos_;
117     readback_pos_ += num_bytes;
118     return buffer_->GetBytesAsString(old_readback_pos, num_bytes);
119   }
120 
BuildNestedMessages(Message * msg,uint32_t max_depth,bool empty=false,uint32_t depth=0)121   static void BuildNestedMessages(Message* msg,
122                                   uint32_t max_depth,
123                                   bool empty = false,
124                                   uint32_t depth = 0) {
125     if (!empty) {
126       for (uint32_t i = 1; i <= 128; ++i)
127         msg->AppendBytes(i, kTestBytes, sizeof(kTestBytes));
128     }
129 
130     if (depth < max_depth) {
131       auto* nested_msg =
132           msg->BeginNestedMessage<FakeChildMessage>(1 + depth * 10);
133       BuildNestedMessages(nested_msg, max_depth, empty, depth + 1);
134     }
135 
136     if (!empty) {
137       for (uint32_t i = 129; i <= 256; ++i)
138         msg->AppendVarInt(i, 42);
139     }
140 
141     if ((depth & 2) == 0)
142       msg->Finalize();
143   }
144 
145  private:
146   std::unique_ptr<FakeScatteredBuffer> buffer_;
147   std::unique_ptr<ScatteredStreamWriter> stream_writer_;
148   std::vector<std::unique_ptr<uint8_t[]>> messages_;
149   size_t chunk_size_{};
150   size_t readback_pos_{};
151 };
152 
TEST_F(MessageTest,ZeroLengthArraysAndStrings)153 TEST_F(MessageTest, ZeroLengthArraysAndStrings) {
154   Message* msg = NewMessage();
155   msg->AppendBytes(1 /* field_id */, nullptr, 0);
156   msg->AppendString(2 /* field_id */, "");
157 
158   EXPECT_EQ(4u, msg->Finalize());
159   EXPECT_EQ(4u, GetNumSerializedBytes());
160 
161   // These lines match the serialization of the Append* calls above.
162   ASSERT_EQ("0A00", GetNextSerializedBytes(2));
163   ASSERT_EQ("1200", GetNextSerializedBytes(2));
164 }
165 
TEST_F(MessageTest,BasicTypesNoNesting)166 TEST_F(MessageTest, BasicTypesNoNesting) {
167   Message* msg = NewMessage();
168   msg->AppendVarInt(1 /* field_id */, 0);
169   msg->AppendVarInt(2 /* field_id */, std::numeric_limits<uint32_t>::max());
170   msg->AppendVarInt(3 /* field_id */, 42);
171   msg->AppendVarInt(4 /* field_id */, std::numeric_limits<uint64_t>::max());
172   msg->AppendFixed(5 /* field_id */, 3.1415f /* float */);
173   msg->AppendFixed(6 /* field_id */, 3.14159265358979323846 /* double */);
174   msg->AppendBytes(7 /* field_id */, kTestBytes, sizeof(kTestBytes));
175 
176   // Field ids > 16 are expected to be varint encoded (preamble > 1 byte)
177   msg->AppendString(257 /* field_id */, "0123456789abcdefABCDEF");
178   msg->AppendSignedVarInt(3 /* field_id */, -21);
179 
180   EXPECT_EQ(74u, msg->Finalize());
181   EXPECT_EQ(74u, GetNumSerializedBytes());
182 
183   // These lines match the serialization of the Append* calls above.
184   ASSERT_EQ("0800", GetNextSerializedBytes(2));
185   ASSERT_EQ("10FFFFFFFF0F", GetNextSerializedBytes(6));
186   ASSERT_EQ("182A", GetNextSerializedBytes(2));
187   ASSERT_EQ("20FFFFFFFFFFFFFFFFFF01", GetNextSerializedBytes(11));
188   ASSERT_EQ("2D560E4940", GetNextSerializedBytes(5));
189   ASSERT_EQ("31182D4454FB210940", GetNextSerializedBytes(9));
190   ASSERT_EQ("3A0A00000000420142FF4200", GetNextSerializedBytes(12));
191   ASSERT_EQ("8A101630313233343536373839616263646566414243444546",
192             GetNextSerializedBytes(25));
193   ASSERT_EQ("1829", GetNextSerializedBytes(2));
194 }
195 
TEST_F(MessageTest,NestedMessagesSimple)196 TEST_F(MessageTest, NestedMessagesSimple) {
197   Message* root_msg = NewMessage();
198   root_msg->AppendVarInt(1 /* field_id */, 1);
199 
200   FakeChildMessage* nested_msg =
201       root_msg->BeginNestedMessage<FakeChildMessage>(128 /* field_id */);
202   ASSERT_EQ(0u, reinterpret_cast<uintptr_t>(nested_msg) % sizeof(void*));
203   nested_msg->AppendVarInt(2 /* field_id */, 2);
204 
205   nested_msg =
206       root_msg->BeginNestedMessage<FakeChildMessage>(129 /* field_id */);
207   nested_msg->AppendVarInt(4 /* field_id */, 2);
208 
209   root_msg->AppendVarInt(5 /* field_id */, 3);
210 
211   // The expected size of the root message is supposed to be 14 bytes:
212   //   2 bytes for the varint field (id: 1) (1 for preamble and one for payload)
213   //   3 bytes for the preamble of the 1st nested message (2 for id, 1 for size)
214   //   2 bytes for the varint field (id: 2) of the 1st nested message
215   //   3 bytes for the premable of the 2nd nested message
216   //   2 bytes for the varint field (id: 4) of the 2nd nested message.
217   //   2 bytes for the last varint (id : 5) field of the root message.
218   // Test also that finalization is idempontent and Finalize() can be safely
219   // called more than once without side effects.
220   for (int i = 0; i < 3; ++i) {
221     EXPECT_EQ(14u, root_msg->Finalize());
222     EXPECT_EQ(14u, GetNumSerializedBytes());
223   }
224 
225   ASSERT_EQ("0801", GetNextSerializedBytes(2));
226 
227   ASSERT_EQ("820802", GetNextSerializedBytes(3));
228   ASSERT_EQ("1002", GetNextSerializedBytes(2));
229 
230   ASSERT_EQ("8A0802", GetNextSerializedBytes(3));
231   ASSERT_EQ("2002", GetNextSerializedBytes(2));
232 
233   ASSERT_EQ("2803", GetNextSerializedBytes(2));
234 }
235 
236 // Tests using a AppendScatteredBytes to append raw bytes to
237 // a message using multiple individual buffers.
TEST_F(MessageTest,AppendScatteredBytes)238 TEST_F(MessageTest, AppendScatteredBytes) {
239   Message* root_msg = NewMessage();
240 
241   uint8_t buffer[42];
242   memset(buffer, 0x42, sizeof(buffer));
243 
244   ContiguousMemoryRange ranges[] = {{buffer, buffer + sizeof(buffer)},
245                                     {buffer, buffer + sizeof(buffer)}};
246   root_msg->AppendScatteredBytes(1 /* field_id */, ranges, 2);
247   EXPECT_EQ(86u, root_msg->Finalize());
248   EXPECT_EQ(86u, GetNumSerializedBytes());
249 
250   // field_id
251   EXPECT_EQ("0A", GetNextSerializedBytes(1));
252   // field length
253   EXPECT_EQ("54", GetNextSerializedBytes(1));
254   // start of contents
255   EXPECT_EQ("42424242", GetNextSerializedBytes(4));
256 }
257 
TEST_F(MessageTest,AppendRawProtoBytesFinalizesNestedMessage)258 TEST_F(MessageTest, AppendRawProtoBytesFinalizesNestedMessage) {
259   Message* root_msg = NewMessage();
260 
261   uint8_t buffer[42];
262   memset(buffer, 0x42, sizeof(buffer));
263 
264   FakeChildMessage* nested_msg =
265       root_msg->BeginNestedMessage<FakeChildMessage>(9001 /* field_id */);
266   nested_msg->AppendVarInt(4 /* field_id */, 2);
267   uint8_t* nested_msg_size_field = nested_msg->size_field();
268 
269   EXPECT_FALSE(nested_msg->is_finalized());
270   EXPECT_EQ(0u, *nested_msg_size_field);
271 
272   root_msg->AppendRawProtoBytes(buffer, sizeof(buffer));
273 
274   // Nested message should have been finalized as a side effect of appending
275   // raw bytes.
276   EXPECT_EQ(0x2u, *nested_msg_size_field);
277 }
278 
TEST_F(MessageTest,AppendScatteredBytesFinalizesNestedMessage)279 TEST_F(MessageTest, AppendScatteredBytesFinalizesNestedMessage) {
280   Message* root_msg = NewMessage();
281 
282   uint8_t buffer[42];
283   memset(buffer, 0x42, sizeof(buffer));
284 
285   FakeChildMessage* nested_msg =
286       root_msg->BeginNestedMessage<FakeChildMessage>(9001 /* field_id */);
287   nested_msg->AppendVarInt(4 /* field_id */, 2);
288   uint8_t* nested_msg_size_field = nested_msg->size_field();
289 
290   EXPECT_FALSE(nested_msg->is_finalized());
291   EXPECT_EQ(0u, *nested_msg_size_field);
292 
293   ContiguousMemoryRange ranges[] = {{buffer, buffer + sizeof(buffer)}};
294   root_msg->AppendScatteredBytes(1 /* field_id */, ranges, 1);
295 
296   // Nested message should have been finalized as a side effect of appending
297   // scattered bytes.
298   EXPECT_EQ(0x2u, *nested_msg_size_field);
299 }
300 
TEST_F(MessageTest,StressTest)301 TEST_F(MessageTest, StressTest) {
302   std::vector<Message*> nested_msgs;
303 
304   Message* root_msg = NewMessage();
305   BuildNestedMessages(root_msg, /*max_depth=*/10);
306   root_msg->Finalize();
307 
308   // The main point of this test is to stress the code paths and test for
309   // unexpected crashes of the production code. The actual serialization is
310   // already covered in the other text fixtures. Keeping just a final smoke test
311   // here on the full buffer hash.
312   std::string full_buf = GetNextSerializedBytes(GetNumSerializedBytes());
313   size_t buf_hash = SimpleHash(full_buf);
314   EXPECT_EQ(0xf9e32b65, buf_hash);
315 }
316 
TEST_F(MessageTest,DeeplyNested)317 TEST_F(MessageTest, DeeplyNested) {
318   Message* root_msg = NewMessage();
319   BuildNestedMessages(root_msg, /*max_depth=*/1000);
320   root_msg->Finalize();
321 
322   std::string full_buf = GetNextSerializedBytes(GetNumSerializedBytes());
323   size_t buf_hash = SimpleHash(full_buf);
324   EXPECT_EQ(0xc0fde419, buf_hash);
325 }
326 
TEST_F(MessageTest,DeeplyNestedEmptyMessages)327 TEST_F(MessageTest, DeeplyNestedEmptyMessages) {
328   // Stress test writing deeply nested empty messages, many of which will be
329   // packed into the protobuf length field.
330 
331   // Use a larger chunk size for this test so there is more opportunity to pack
332   // messages.
333   SetChunkSize(4096u);
334 
335   Message* root_msg = NewMessage();
336   BuildNestedMessages(root_msg, /*max_depth=*/1000, /*empty=*/true);
337   root_msg->Finalize();
338 
339   std::string full_buf = GetNextSerializedBytes(GetNumSerializedBytes());
340   size_t buf_hash = SimpleHash(full_buf);
341   EXPECT_EQ(0x9371fe8eu, buf_hash);
342 }
343 
TEST_F(MessageTest,DestructInvalidMessageHandle)344 TEST_F(MessageTest, DestructInvalidMessageHandle) {
345   FakeRootMessage* msg = NewMessage();
346   EXPECT_DCHECK_DEATH({
347     MessageHandle<FakeRootMessage> handle(msg);
348     ResetMessage(msg);
349   });
350 }
351 
TEST_F(MessageTest,MessageHandle)352 TEST_F(MessageTest, MessageHandle) {
353   FakeRootMessage* msg3 = NewMessageWithSizeField();
354   FakeRootMessage* msg2 = NewMessageWithSizeField();
355   FakeRootMessage* msg1 = NewMessageWithSizeField();
356   FakeRootMessage* ignored_msg = NewMessage();
357   uint8_t* msg1_size = msg1->size_field();
358   uint8_t* msg2_size = msg2->size_field();
359   uint8_t* msg3_size = msg3->size_field();
360 
361   // Test that the handle going out of scope causes the finalization of the
362   // target message and triggers the optional callback.
363   {
364     MessageHandle<FakeRootMessage> handle1(msg1);
365     handle1->AppendBytes(1 /* field_id */, kTestBytes, 1 /* size */);
366     ASSERT_EQ(0u, msg1_size[0]);
367   }
368   ASSERT_EQ(0x3u, msg1_size[0]);
369 
370   // Test that the handle can be late initialized.
371   MessageHandle<FakeRootMessage> handle2(ignored_msg);
372   handle2 = MessageHandle<FakeRootMessage>(msg2);
373   handle2->AppendBytes(1 /* field_id */, kTestBytes, 2 /* size */);
374   ASSERT_EQ(0u, msg2_size[0]);  // |msg2| should not be finalized yet.
375 
376   // Test that std::move works and does NOT cause finalization of the moved
377   // message.
378   MessageHandle<FakeRootMessage> handle_swp(ignored_msg);
379   handle_swp = std::move(handle2);
380   ASSERT_EQ(0u, msg2_size[0]);  // msg2 should be NOT finalized yet.
381   handle_swp->AppendBytes(2 /* field_id */, kTestBytes, 3 /* size */);
382 
383   MessageHandle<FakeRootMessage> handle3(msg3);
384   handle3->AppendBytes(1 /* field_id */, kTestBytes, 4 /* size */);
385   ASSERT_EQ(0u, msg3_size[0]);  // msg2 should be NOT finalized yet.
386 
387   // Both |handle3| and |handle_swp| point to a valid message (respectively,
388   // |msg3| and |msg2|). Now move |handle3| into |handle_swp|.
389   handle_swp = std::move(handle3);
390   ASSERT_EQ(0x89u, msg2_size[0]);  // |msg2| should be finalized at this point.
391 
392   // At this point writing into handle_swp should actually write into |msg3|.
393   ASSERT_EQ(msg3, &*handle_swp);
394   handle_swp->AppendBytes(2 /* field_id */, kTestBytes, 8 /* size */);
395   MessageHandle<FakeRootMessage> another_handle(ignored_msg);
396   handle_swp = std::move(another_handle);
397   ASSERT_EQ(0x90u, msg3_size[0]);  // |msg3| should be finalized at this point.
398 
399 #if PERFETTO_DCHECK_IS_ON()
400   // In developer builds w/ PERFETTO_DCHECK on a finalized message should
401   // invalidate the handle, in order to early catch bugs in the client code.
402   FakeRootMessage* msg4 = NewMessage();
403   MessageHandle<FakeRootMessage> handle4(msg4);
404   ASSERT_EQ(msg4, &*handle4);
405   msg4->Finalize();
406   ASSERT_EQ(nullptr, &*handle4);
407 #endif
408 
409   // Test also the behavior of handle with non-root (nested) messages.
410 
411   uint8_t* size_msg_2;
412   {
413     auto* nested_msg_1 = NewMessage()->BeginNestedMessage<FakeChildMessage>(3);
414     MessageHandle<FakeChildMessage> child_handle_1(nested_msg_1);
415     uint8_t* size_msg_1 = nested_msg_1->size_field();
416     memset(size_msg_1, 0, proto_utils::kMessageLengthFieldSize);
417     child_handle_1->AppendVarInt(1, 0x11);
418 
419     auto* nested_msg_2 = NewMessage()->BeginNestedMessage<FakeChildMessage>(2);
420     size_msg_2 = nested_msg_2->size_field();
421     memset(size_msg_2, 0, proto_utils::kMessageLengthFieldSize);
422     MessageHandle<FakeChildMessage> child_handle_2(nested_msg_2);
423     child_handle_2->AppendVarInt(2, 0xFF);
424 
425     // |nested_msg_1| should not be finalized yet.
426     ASSERT_EQ(0u, size_msg_1[0]);
427 
428     // This move should cause |nested_msg_1| to be finalized, but not
429     // |nested_msg_2|, which will be finalized only after the current scope.
430     child_handle_1 = std::move(child_handle_2);
431     ASSERT_EQ(0x82u, size_msg_1[0]);
432     ASSERT_EQ(0u, size_msg_2[0]);
433   }
434   ASSERT_EQ(0x3u, size_msg_2[0]);
435 }
436 
TEST_F(MessageTest,MoveMessageHandle)437 TEST_F(MessageTest, MoveMessageHandle) {
438   FakeRootMessage* msg = NewMessageWithSizeField();
439   uint8_t* msg_size = msg->size_field();
440 
441   // Test that the handle going out of scope causes the finalization of the
442   // target message.
443   {
444     MessageHandle<FakeRootMessage> handle1(msg);
445     MessageHandle<FakeRootMessage> handle2{};
446     handle1->AppendBytes(1 /* field_id */, kTestBytes, 1 /* size */);
447     handle2 = std::move(handle1);
448     ASSERT_EQ(0u, msg_size[0]);
449   }
450   ASSERT_EQ(0x3u, msg_size[0]);
451 }
452 
TEST_F(MessageTest,FinalizeWithCompaction)453 TEST_F(MessageTest, FinalizeWithCompaction) {
454   FakeRootMessage* msg = NewMessageWithSizeField();
455 
456   msg->AppendBytes(1 /* field_id */, kTestBytes, 5 /* size */);
457   uint32_t size = msg->Finalize();
458   EXPECT_EQ(7u, size);
459   EXPECT_EQ(8u, GetNumSerializedBytes());
460 }
461 
TEST_F(MessageTest,FinalizeWithoutCompaction)462 TEST_F(MessageTest, FinalizeWithoutCompaction) {
463   FakeRootMessage* msg = NewMessageWithSizeField();
464 
465   // This message doesn't fit into a single chunk, so it won't be compacted.
466   msg->AppendBytes(1 /* field_id */, kTestBytes, sizeof(kTestBytes) /* size */);
467   msg->AppendBytes(1 /* field_id */, kTestBytes, sizeof(kTestBytes) /* size */);
468   uint32_t size = msg->Finalize();
469   EXPECT_EQ(24u, size);
470   EXPECT_EQ(28u, GetNumSerializedBytes());
471 }
472 
473 }  // namespace
474 }  // namespace protozero
475