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