blob: 7240f7e0ed3d5d807bd58b70536251132c1e86d8 [file] [log] [blame]
Primiano Tucci4f9b6d72017-12-05 20:59:16 +00001/*
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
Hector Dearmane1e56b62018-02-21 19:11:58 +000017#include "perfetto/protozero/message.h"
18#include "perfetto/protozero/message_handle.h"
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000019
20#include <limits>
21#include <memory>
22#include <utility>
23#include <vector>
24
25#include "gtest/gtest.h"
26#include "perfetto/base/logging.h"
27#include "src/protozero/test/fake_scattered_buffer.h"
28
29namespace protozero {
30
31namespace {
32
Florian Mayerdbd08782018-03-21 14:07:51 +000033constexpr size_t kChunkSize = 16;
34constexpr uint8_t kTestBytes[] = {0, 0, 0, 0, 0x42, 1, 0x42, 0xff, 0x42, 0};
35constexpr const char kStartWatermark[] = {'a', 'b', 'c', 'd',
36 '1', '2', '3', '\0'};
37constexpr const char kEndWatermark[] = {'9', '8', '7', '6',
38 'z', 'w', 'y', '\0'};
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000039
Hector Dearmanaaa4c192018-02-19 11:57:35 +000040class FakeRootMessage : public Message {};
41class FakeChildMessage : public Message {};
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000042
43uint32_t SimpleHash(const std::string& str) {
44 uint32_t hash = 5381;
45 for (char c : str)
46 hash = 33 * hash + static_cast<uint32_t>(c);
47 return hash;
48}
49
Hector Dearmanaaa4c192018-02-19 11:57:35 +000050class MessageTest : public ::testing::Test {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000051 public:
52 void SetUp() override {
53 buffer_.reset(new FakeScatteredBuffer(kChunkSize));
54 stream_writer_.reset(new ScatteredStreamWriter(buffer_.get()));
55 readback_pos_ = 0;
56 }
57
58 void TearDown() override {
59 // Check that none of the messages created by the text fixtures below did
60 // under/overflow their heap boundaries.
61 for (std::unique_ptr<uint8_t[]>& mem : messages_) {
62 EXPECT_STREQ(kStartWatermark, reinterpret_cast<char*>(mem.get()));
63 EXPECT_STREQ(kEndWatermark,
64 reinterpret_cast<char*>(mem.get() + sizeof(kStartWatermark) +
Hector Dearmanaaa4c192018-02-19 11:57:35 +000065 sizeof(Message)));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000066 mem.reset();
67 }
68 messages_.clear();
69 stream_writer_.reset();
70 buffer_.reset();
71 }
72
Florian Mayer8a8044f2018-01-11 16:03:09 +000073 void ResetMessage(FakeRootMessage* msg) { msg->Reset(stream_writer_.get()); }
74
Primiano Tucci4f9b6d72017-12-05 20:59:16 +000075 FakeRootMessage* NewMessage() {
76 std::unique_ptr<uint8_t[]> mem(
77 new uint8_t[sizeof(kStartWatermark) + sizeof(FakeRootMessage) +
78 sizeof(kEndWatermark)]);
79 uint8_t* msg_start = mem.get() + sizeof(kStartWatermark);
80 memcpy(mem.get(), kStartWatermark, sizeof(kStartWatermark));
81 memset(msg_start, 0, sizeof(FakeRootMessage));
82 memcpy(msg_start + sizeof(FakeRootMessage), kEndWatermark,
83 sizeof(kEndWatermark));
84 messages_.push_back(std::move(mem));
85 FakeRootMessage* msg = reinterpret_cast<FakeRootMessage*>(msg_start);
86 msg->Reset(stream_writer_.get());
87 return msg;
88 }
89
90 size_t GetNumSerializedBytes() {
91 if (buffer_->chunks().empty())
92 return 0;
93 return buffer_->chunks().size() * kChunkSize -
94 stream_writer_->bytes_available();
95 }
96
97 std::string GetNextSerializedBytes(size_t num_bytes) {
98 size_t old_readback_pos = readback_pos_;
99 readback_pos_ += num_bytes;
100 return buffer_->GetBytesAsString(old_readback_pos, num_bytes);
101 }
102
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000103 static void BuildNestedMessages(Message* msg, uint32_t depth = 0) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000104 for (uint32_t i = 1; i <= 128; ++i)
105 msg->AppendBytes(i, kTestBytes, sizeof(kTestBytes));
106
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000107 if (depth < Message::kMaxNestingDepth) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000108 auto* nested_msg =
109 msg->BeginNestedMessage<FakeChildMessage>(1 + depth * 10);
110 BuildNestedMessages(nested_msg, depth + 1);
111 }
112
113 for (uint32_t i = 129; i <= 256; ++i)
114 msg->AppendVarInt(i, 42);
115
116 if ((depth & 2) == 0)
117 msg->Finalize();
118 }
119
120 private:
121 std::unique_ptr<FakeScatteredBuffer> buffer_;
122 std::unique_ptr<ScatteredStreamWriter> stream_writer_;
123 std::vector<std::unique_ptr<uint8_t[]>> messages_;
124 size_t readback_pos_;
125};
126
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000127TEST_F(MessageTest, ZeroLengthArraysAndStrings) {
128 Message* msg = NewMessage();
Hector Dearman8bf3e252018-01-26 11:33:58 +0000129 msg->AppendBytes(1 /* field_id */, nullptr, 0);
130 msg->AppendString(2 /* field_id */, "");
131
132 EXPECT_EQ(4u, msg->Finalize());
133 EXPECT_EQ(4u, GetNumSerializedBytes());
134
135 // These lines match the serialization of the Append* calls above.
136 ASSERT_EQ("0A00", GetNextSerializedBytes(2));
137 ASSERT_EQ("1200", GetNextSerializedBytes(2));
138}
139
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000140TEST_F(MessageTest, BasicTypesNoNesting) {
141 Message* msg = NewMessage();
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000142 msg->AppendVarInt(1 /* field_id */, 0);
143 msg->AppendVarInt(2 /* field_id */, std::numeric_limits<uint32_t>::max());
144 msg->AppendVarInt(3 /* field_id */, 42);
145 msg->AppendVarInt(4 /* field_id */, std::numeric_limits<uint64_t>::max());
146 msg->AppendFixed(5 /* field_id */, 3.1415f /* float */);
147 msg->AppendFixed(6 /* field_id */, 3.14159265358979323846 /* double */);
148 msg->AppendBytes(7 /* field_id */, kTestBytes, sizeof(kTestBytes));
149
150 // Field ids > 16 are expected to be varint encoded (preamble > 1 byte)
151 msg->AppendString(257 /* field_id */, "0123456789abcdefABCDEF");
152 msg->AppendSignedVarInt(3 /* field_id */, -21);
153
154 EXPECT_EQ(74u, msg->Finalize());
155 EXPECT_EQ(74u, GetNumSerializedBytes());
156
157 // These lines match the serialization of the Append* calls above.
158 ASSERT_EQ("0800", GetNextSerializedBytes(2));
159 ASSERT_EQ("10FFFFFFFF0F", GetNextSerializedBytes(6));
160 ASSERT_EQ("182A", GetNextSerializedBytes(2));
161 ASSERT_EQ("20FFFFFFFFFFFFFFFFFF01", GetNextSerializedBytes(11));
162 ASSERT_EQ("2D560E4940", GetNextSerializedBytes(5));
163 ASSERT_EQ("31182D4454FB210940", GetNextSerializedBytes(9));
164 ASSERT_EQ("3A0A00000000420142FF4200", GetNextSerializedBytes(12));
165 ASSERT_EQ("8A101630313233343536373839616263646566414243444546",
166 GetNextSerializedBytes(25));
167 ASSERT_EQ("1829", GetNextSerializedBytes(2));
168}
169
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000170TEST_F(MessageTest, NestedMessagesSimple) {
171 Message* root_msg = NewMessage();
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000172 root_msg->AppendVarInt(1 /* field_id */, 1);
173
174 FakeChildMessage* nested_msg =
175 root_msg->BeginNestedMessage<FakeChildMessage>(128 /* field_id */);
176 ASSERT_EQ(0u, reinterpret_cast<uintptr_t>(nested_msg) % sizeof(void*));
177 nested_msg->AppendVarInt(2 /* field_id */, 2);
178
179 nested_msg =
180 root_msg->BeginNestedMessage<FakeChildMessage>(129 /* field_id */);
181 nested_msg->AppendVarInt(4 /* field_id */, 2);
182
183 root_msg->AppendVarInt(5 /* field_id */, 3);
184
185 // The expected size of the root message is supposed to be 20 bytes:
186 // 2 bytes for the varint field (id: 1) (1 for preamble and one for payload)
187 // 6 bytes for the preamble of the 1st nested message (2 for id, 4 for size)
188 // 2 bytes for the varint field (id: 2) of the 1st nested message
189 // 6 bytes for the premable of the 2nd nested message
190 // 2 bytes for the varint field (id: 4) of the 2nd nested message.
191 // 2 bytes for the last varint (id : 5) field of the root message.
192 // Test also that finalization is idempontent and Finalize() can be safely
193 // called more than once without side effects.
194 for (int i = 0; i < 3; ++i) {
195 EXPECT_EQ(20u, root_msg->Finalize());
196 EXPECT_EQ(20u, GetNumSerializedBytes());
197 }
198
199 ASSERT_EQ("0801", GetNextSerializedBytes(2));
200
201 ASSERT_EQ("820882808000", GetNextSerializedBytes(6));
202 ASSERT_EQ("1002", GetNextSerializedBytes(2));
203
204 ASSERT_EQ("8A0882808000", GetNextSerializedBytes(6));
205 ASSERT_EQ("2002", GetNextSerializedBytes(2));
206
207 ASSERT_EQ("2803", GetNextSerializedBytes(2));
208}
209
210// Checks that the size field of root and nested messages is properly written
211// on finalization.
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000212TEST_F(MessageTest, BackfillSizeOnFinalization) {
213 Message* root_msg = NewMessage();
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000214 uint8_t root_msg_size[proto_utils::kMessageLengthFieldSize] = {};
Primiano Tucci3a918872017-12-18 10:53:39 +0100215 root_msg->set_size_field(&root_msg_size[0]);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000216 root_msg->AppendVarInt(1, 0x42);
217
218 FakeChildMessage* nested_msg_1 =
219 root_msg->BeginNestedMessage<FakeChildMessage>(2);
220 nested_msg_1->AppendVarInt(3, 0x43);
221
222 FakeChildMessage* nested_msg_2 =
223 nested_msg_1->BeginNestedMessage<FakeChildMessage>(4);
224 uint8_t buf200[200];
225 memset(buf200, 0x42, sizeof(buf200));
226 nested_msg_2->AppendBytes(5, buf200, sizeof(buf200));
227
Primiano Tucci3a918872017-12-18 10:53:39 +0100228 root_msg->inc_size_already_written(6);
229
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000230 // The value returned by Finalize() should be == the full size of |root_msg|.
231 EXPECT_EQ(217u, root_msg->Finalize());
232 EXPECT_EQ(217u, GetNumSerializedBytes());
233
234 // However the size written in the size field should take into account the
235 // inc_size_already_written() call and be equal to 118 - 6 = 112, encoded
236 // in a rendundant varint encoding of kMessageLengthFieldSize bytes.
Primiano Tucci3a918872017-12-18 10:53:39 +0100237 EXPECT_STREQ("\xD3\x81\x80\x00", reinterpret_cast<char*>(root_msg_size));
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000238
239 // Skip 2 bytes for the 0x42 varint + 1 byte for the |nested_msg_1| preamble.
240 GetNextSerializedBytes(3);
241
242 // Check that the size of |nested_msg_1| was backfilled. Its size is:
243 // 203 bytes for |nest_mesg_2| (see below) + 5 bytes for its preamble +
244 // 2 bytes for the 0x43 varint = 210 bytes.
245 EXPECT_EQ("D2818000", GetNextSerializedBytes(4));
246
247 // Skip 2 bytes for the 0x43 varint + 1 byte for the |nested_msg_2| preamble.
248 GetNextSerializedBytes(3);
249
250 // Check that the size of |nested_msg_2| was backfilled. Its size is:
251 // 200 bytes (for |buf200|) + 3 bytes for its preamble = 203 bytes.
252 EXPECT_EQ("CB818000", GetNextSerializedBytes(4));
253}
254
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000255TEST_F(MessageTest, StressTest) {
256 std::vector<Message*> nested_msgs;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000257
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000258 Message* root_msg = NewMessage();
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000259 BuildNestedMessages(root_msg);
260 root_msg->Finalize();
261
262 // The main point of this test is to stress the code paths and test for
263 // unexpected crashes of the production code. The actual serialization is
264 // already covered in the other text fixtures. Keeping just a final smoke test
265 // here on the full buffer hash.
266 std::string full_buf = GetNextSerializedBytes(GetNumSerializedBytes());
267 size_t buf_hash = SimpleHash(full_buf);
268 EXPECT_EQ(0xfd19cc0a, buf_hash);
269}
270
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000271TEST_F(MessageTest, DestructInvalidMessageHandle) {
Florian Mayer8a8044f2018-01-11 16:03:09 +0000272 FakeRootMessage* msg = NewMessage();
273 EXPECT_DEBUG_DEATH(
274 {
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000275 MessageHandle<FakeRootMessage> handle(msg);
Florian Mayer8a8044f2018-01-11 16:03:09 +0000276 ResetMessage(msg);
277 },
278 "");
279}
280
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000281TEST_F(MessageTest, MessageHandle) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000282 FakeRootMessage* msg1 = NewMessage();
283 FakeRootMessage* msg2 = NewMessage();
284 FakeRootMessage* msg3 = NewMessage();
285 FakeRootMessage* ignored_msg = NewMessage();
286 uint8_t msg1_size[proto_utils::kMessageLengthFieldSize] = {};
287 uint8_t msg2_size[proto_utils::kMessageLengthFieldSize] = {};
288 uint8_t msg3_size[proto_utils::kMessageLengthFieldSize] = {};
Primiano Tucci3a918872017-12-18 10:53:39 +0100289 msg1->set_size_field(&msg1_size[0]);
290 msg2->set_size_field(&msg2_size[0]);
291 msg3->set_size_field(&msg3_size[0]);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000292
293 // Test that the handle going out of scope causes the finalization of the
294 // target message and triggers the optional callback.
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000295 {
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000296 MessageHandle<FakeRootMessage> handle1(msg1);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000297 handle1->AppendBytes(1 /* field_id */, kTestBytes, 1 /* size */);
298 ASSERT_EQ(0u, msg1_size[0]);
299 }
300 ASSERT_EQ(0x83u, msg1_size[0]);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000301
302 // Test that the handle can be late initialized.
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000303 MessageHandle<FakeRootMessage> handle2(ignored_msg);
304 handle2 = MessageHandle<FakeRootMessage>(msg2);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000305 handle2->AppendBytes(1 /* field_id */, kTestBytes, 2 /* size */);
306 ASSERT_EQ(0u, msg2_size[0]); // |msg2| should not be finalized yet.
307
308 // Test that std::move works and does NOT cause finalization of the moved
309 // message.
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000310 MessageHandle<FakeRootMessage> handle_swp(ignored_msg);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000311 handle_swp = std::move(handle2);
312 ASSERT_EQ(0u, msg2_size[0]); // msg2 should be NOT finalized yet.
313 handle_swp->AppendBytes(2 /* field_id */, kTestBytes, 3 /* size */);
314
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000315 MessageHandle<FakeRootMessage> handle3(msg3);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000316 handle3->AppendBytes(1 /* field_id */, kTestBytes, 4 /* size */);
317 ASSERT_EQ(0u, msg3_size[0]); // msg2 should be NOT finalized yet.
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000318
319 // Both |handle3| and |handle_swp| point to a valid message (respectively,
320 // |msg3| and |msg2|). Now move |handle3| into |handle_swp|.
321 handle_swp = std::move(handle3);
322 ASSERT_EQ(0x89u, msg2_size[0]); // |msg2| should be finalized at this point.
323
324 // At this point writing into handle_swp should actually write into |msg3|.
325 ASSERT_EQ(msg3, &*handle_swp);
326 handle_swp->AppendBytes(2 /* field_id */, kTestBytes, 8 /* size */);
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000327 MessageHandle<FakeRootMessage> another_handle(ignored_msg);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000328 handle_swp = std::move(another_handle);
329 ASSERT_EQ(0x90u, msg3_size[0]); // |msg3| should be finalized at this point.
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000330
Florian Mayer8a8044f2018-01-11 16:03:09 +0000331#if PERFETTO_DCHECK_IS_ON()
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000332 // In developer builds w/ PERFETTO_DCHECK on a finalized message should
333 // invalidate the handle, in order to early catch bugs in the client code.
334 FakeRootMessage* msg4 = NewMessage();
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000335 MessageHandle<FakeRootMessage> handle4(msg4);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000336 ASSERT_EQ(msg4, &*handle4);
337 msg4->Finalize();
338 ASSERT_EQ(nullptr, &*handle4);
339#endif
340
341 // Test also the behavior of handle with non-root (nested) messages.
342
Primiano Tucci3a918872017-12-18 10:53:39 +0100343 uint8_t* size_msg_2;
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000344 {
345 auto* nested_msg_1 = NewMessage()->BeginNestedMessage<FakeChildMessage>(3);
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000346 MessageHandle<FakeChildMessage> child_handle_1(nested_msg_1);
Primiano Tucci3a918872017-12-18 10:53:39 +0100347 uint8_t* size_msg_1 = nested_msg_1->size_field();
348 memset(size_msg_1, 0, proto_utils::kMessageLengthFieldSize);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000349 child_handle_1->AppendVarInt(1, 0x11);
350
351 auto* nested_msg_2 = NewMessage()->BeginNestedMessage<FakeChildMessage>(2);
352 size_msg_2 = nested_msg_2->size_field();
Primiano Tucci3a918872017-12-18 10:53:39 +0100353 memset(size_msg_2, 0, proto_utils::kMessageLengthFieldSize);
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000354 MessageHandle<FakeChildMessage> child_handle_2(nested_msg_2);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000355 child_handle_2->AppendVarInt(2, 0xFF);
356
357 // |nested_msg_1| should not be finalized yet.
Primiano Tucci3a918872017-12-18 10:53:39 +0100358 ASSERT_EQ(0u, size_msg_1[0]);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000359
360 // This move should cause |nested_msg_1| to be finalized, but not
361 // |nested_msg_2|, which will be finalized only after the current scope.
362 child_handle_1 = std::move(child_handle_2);
Primiano Tucci3a918872017-12-18 10:53:39 +0100363 ASSERT_EQ(0x82u, size_msg_1[0]);
364 ASSERT_EQ(0u, size_msg_2[0]);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000365 }
Primiano Tucci3a918872017-12-18 10:53:39 +0100366 ASSERT_EQ(0x83u, size_msg_2[0]);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000367}
368
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000369TEST_F(MessageTest, MoveMessageHandle) {
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000370 FakeRootMessage* msg = NewMessage();
371 uint8_t msg_size[proto_utils::kMessageLengthFieldSize] = {};
Primiano Tucci3a918872017-12-18 10:53:39 +0100372 msg->set_size_field(&msg_size[0]);
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000373
374 // Test that the handle going out of scope causes the finalization of the
375 // target message.
376 {
Hector Dearmanaaa4c192018-02-19 11:57:35 +0000377 MessageHandle<FakeRootMessage> handle1(msg);
378 MessageHandle<FakeRootMessage> handle2{};
Primiano Tucci4f9b6d72017-12-05 20:59:16 +0000379 handle1->AppendBytes(1 /* field_id */, kTestBytes, 1 /* size */);
380 handle2 = std::move(handle1);
381 ASSERT_EQ(0u, msg_size[0]);
382 }
383 ASSERT_EQ(0x83u, msg_size[0]);
384}
385
386} // namespace
387} // namespace protozero