Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(69)

Side by Side Diff: components/tracing/core/proto_zero_message_unittest.cc

Issue 2158323005: tracing v2: Introduce handles for safe usage of ProtoZeroMessage (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: final nits Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « components/tracing/core/proto_zero_message_handle.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/tracing/core/proto_zero_message.h" 5 #include "components/tracing/core/proto_zero_message.h"
6 6
7 #include <limits> 7 #include <limits>
8 #include <memory> 8 #include <memory>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/hash.h" 11 #include "base/hash.h"
12 #include "components/tracing/core/proto_utils.h" 12 #include "components/tracing/core/proto_utils.h"
13 #include "components/tracing/core/proto_zero_message_handle.h"
13 #include "components/tracing/test/fake_scattered_buffer.h" 14 #include "components/tracing/test/fake_scattered_buffer.h"
14 #include "testing/gtest/include/gtest/gtest.h" 15 #include "testing/gtest/include/gtest/gtest.h"
15 16
16 namespace tracing { 17 namespace tracing {
17 namespace v2 { 18 namespace v2 {
18 19
19 const size_t kChunkSize = 16; 20 const size_t kChunkSize = 16;
20 const uint8_t kTestBytes[] = {0, 0, 0, 0, 0x42, 1, 0x42, 0xff, 0x42, 0}; 21 const uint8_t kTestBytes[] = {0, 0, 0, 0, 0x42, 1, 0x42, 0xff, 0x42, 0};
21 const char kStartWatermark[] = {'a', 'b', 'c', 'd', '1', '2', '3', '\0'}; 22 const char kStartWatermark[] = {'a', 'b', 'c', 'd', '1', '2', '3', '\0'};
22 const char kEndWatermark[] = {'9', '8', '7', '6', 'z', 'w', 'y', '\0'}; 23 const char kEndWatermark[] = {'9', '8', '7', '6', 'z', 'w', 'y', '\0'};
23 24
24 class FakeMessage : public ProtoZeroMessage { 25 class FakeRootMessage : public ProtoZeroMessage {};
25 public: 26 class FakeChildMessage : public ProtoZeroMessage {};
26 };
27 27
28 class ProtoZeroMessageTest : public ::testing::Test { 28 class ProtoZeroMessageTest : public ::testing::Test {
29 public: 29 public:
30 void SetUp() override { 30 void SetUp() override {
31 buffer_.reset(new FakeScatteredBuffer(kChunkSize)); 31 buffer_.reset(new FakeScatteredBuffer(kChunkSize));
32 stream_writer_.reset(new ScatteredStreamWriter(buffer_.get())); 32 stream_writer_.reset(new ScatteredStreamWriter(buffer_.get()));
33 readback_pos_ = 0; 33 readback_pos_ = 0;
34 } 34 }
35 35
36 void TearDown() override { 36 void TearDown() override {
37 // Check that none of the messages created by the text fixtures below did 37 // Check that none of the messages created by the text fixtures below did
38 // under/overflow their heap boundaries. 38 // under/overflow their heap boundaries.
39 for (std::unique_ptr<uint8_t[]>& mem : messages_) { 39 for (std::unique_ptr<uint8_t[]>& mem : messages_) {
40 EXPECT_STREQ(kStartWatermark, reinterpret_cast<char*>(mem.get())); 40 EXPECT_STREQ(kStartWatermark, reinterpret_cast<char*>(mem.get()));
41 EXPECT_STREQ(kEndWatermark, 41 EXPECT_STREQ(kEndWatermark,
42 reinterpret_cast<char*>(mem.get() + sizeof(kStartWatermark) + 42 reinterpret_cast<char*>(mem.get() + sizeof(kStartWatermark) +
43 sizeof(ProtoZeroMessage))); 43 sizeof(ProtoZeroMessage)));
44 mem.reset(); 44 mem.reset();
45 } 45 }
46 messages_.clear(); 46 messages_.clear();
47 stream_writer_.reset(); 47 stream_writer_.reset();
48 buffer_.reset(); 48 buffer_.reset();
49 } 49 }
50 50
51 ProtoZeroMessage* NewMessage() { 51 FakeRootMessage* NewMessage() {
52 std::unique_ptr<uint8_t[]> mem( 52 std::unique_ptr<uint8_t[]> mem(
53 new uint8_t[sizeof(kStartWatermark) + sizeof(ProtoZeroMessage) + 53 new uint8_t[sizeof(kStartWatermark) + sizeof(FakeRootMessage) +
54 sizeof(kEndWatermark)]); 54 sizeof(kEndWatermark)]);
55 uint8_t* msg_start = mem.get() + sizeof(kStartWatermark); 55 uint8_t* msg_start = mem.get() + sizeof(kStartWatermark);
56 memcpy(mem.get(), kStartWatermark, sizeof(kStartWatermark)); 56 memcpy(mem.get(), kStartWatermark, sizeof(kStartWatermark));
57 memset(msg_start, 0, sizeof(ProtoZeroMessage)); 57 memset(msg_start, 0, sizeof(FakeRootMessage));
58 memcpy(msg_start + sizeof(ProtoZeroMessage), kEndWatermark, 58 memcpy(msg_start + sizeof(FakeRootMessage), kEndWatermark,
59 sizeof(kEndWatermark)); 59 sizeof(kEndWatermark));
60 messages_.push_back(std::move(mem)); 60 messages_.push_back(std::move(mem));
61 ProtoZeroMessage* msg = reinterpret_cast<ProtoZeroMessage*>(msg_start); 61 FakeRootMessage* msg = reinterpret_cast<FakeRootMessage*>(msg_start);
62 msg->Reset(stream_writer_.get()); 62 msg->Reset(stream_writer_.get());
63 return msg; 63 return msg;
64 } 64 }
65 65
66 size_t GetNumSerializedBytes() { 66 size_t GetNumSerializedBytes() {
67 if (buffer_->chunks().empty()) 67 if (buffer_->chunks().empty())
68 return 0; 68 return 0;
69 return buffer_->chunks().size() * kChunkSize - 69 return buffer_->chunks().size() * kChunkSize -
70 stream_writer_->bytes_available(); 70 stream_writer_->bytes_available();
71 } 71 }
72 72
73 std::string GetNextSerializedBytes(size_t num_bytes) { 73 std::string GetNextSerializedBytes(size_t num_bytes) {
74 size_t old_readback_pos = readback_pos_; 74 size_t old_readback_pos = readback_pos_;
75 readback_pos_ += num_bytes; 75 readback_pos_ += num_bytes;
76 return buffer_->GetBytesAsString(old_readback_pos, num_bytes); 76 return buffer_->GetBytesAsString(old_readback_pos, num_bytes);
77 } 77 }
78 78
79 static void BuildNestedMessages(uint32_t depth, ProtoZeroMessage* msg) { 79 static void BuildNestedMessages(uint32_t depth, ProtoZeroMessage* msg) {
80 for (uint32_t i = 1; i <= 128; ++i) 80 for (uint32_t i = 1; i <= 128; ++i)
81 msg->AppendBytes(i, kTestBytes, sizeof(kTestBytes)); 81 msg->AppendBytes(i, kTestBytes, sizeof(kTestBytes));
82 82
83 if (depth < ProtoZeroMessage::kMaxNestingDepth) { 83 if (depth < ProtoZeroMessage::kMaxNestingDepth) {
84 auto* child_msg = msg->BeginNestedMessage<FakeMessage>(1 + depth * 10); 84 auto* nested_msg =
85 BuildNestedMessages(depth + 1, child_msg); 85 msg->BeginNestedMessage<FakeChildMessage>(1 + depth * 10);
86 BuildNestedMessages(depth + 1, nested_msg);
86 } 87 }
87 88
88 for (uint32_t i = 129; i <= 256; ++i) 89 for (uint32_t i = 129; i <= 256; ++i)
89 msg->AppendVarIntU32(i, 42); 90 msg->AppendVarIntU32(i, 42);
90 91
91 if ((depth & 2) == 0) 92 if ((depth & 2) == 0)
92 msg->Finalize(); 93 msg->Finalize();
93 } 94 }
94 95
95 private: 96 private:
(...skipping 28 matching lines...) Expand all
124 ASSERT_EQ("31182D4454FB210940", GetNextSerializedBytes(9)); 125 ASSERT_EQ("31182D4454FB210940", GetNextSerializedBytes(9));
125 ASSERT_EQ("3A0A00000000420142FF4200", GetNextSerializedBytes(12)); 126 ASSERT_EQ("3A0A00000000420142FF4200", GetNextSerializedBytes(12));
126 ASSERT_EQ("8A101630313233343536373839616263646566414243444546", 127 ASSERT_EQ("8A101630313233343536373839616263646566414243444546",
127 GetNextSerializedBytes(25)); 128 GetNextSerializedBytes(25));
128 } 129 }
129 130
130 TEST_F(ProtoZeroMessageTest, NestedMessagesSimple) { 131 TEST_F(ProtoZeroMessageTest, NestedMessagesSimple) {
131 ProtoZeroMessage* root_msg = NewMessage(); 132 ProtoZeroMessage* root_msg = NewMessage();
132 root_msg->AppendVarIntU32(1 /* field_id */, 1); 133 root_msg->AppendVarIntU32(1 /* field_id */, 1);
133 134
134 FakeMessage* nested_msg = 135 FakeChildMessage* nested_msg =
135 root_msg->BeginNestedMessage<FakeMessage>(128 /* field_id */); 136 root_msg->BeginNestedMessage<FakeChildMessage>(128 /* field_id */);
136 ASSERT_EQ(0u, reinterpret_cast<uintptr_t>(nested_msg) % sizeof(void*)); 137 ASSERT_EQ(0u, reinterpret_cast<uintptr_t>(nested_msg) % sizeof(void*));
137 nested_msg->AppendVarIntU32(2 /* field_id */, 2); 138 nested_msg->AppendVarIntU32(2 /* field_id */, 2);
138 139
139 nested_msg = root_msg->BeginNestedMessage<FakeMessage>(129 /* field_id */); 140 nested_msg =
141 root_msg->BeginNestedMessage<FakeChildMessage>(129 /* field_id */);
140 nested_msg->AppendVarIntU32(4 /* field_id */, 2); 142 nested_msg->AppendVarIntU32(4 /* field_id */, 2);
141 143
142 root_msg->AppendVarIntU32(5 /* field_id */, 3); 144 root_msg->AppendVarIntU32(5 /* field_id */, 3);
143 145
144 // The expected size of the root message is supposed to be 20 bytes: 146 // The expected size of the root message is supposed to be 20 bytes:
145 // 2 bytes for the varint field (id: 1) (1 for preamble and one for payload) 147 // 2 bytes for the varint field (id: 1) (1 for preamble and one for payload)
146 // 6 bytes for the preamble of the 1st nested message (2 for id, 4 for size) 148 // 6 bytes for the preamble of the 1st nested message (2 for id, 4 for size)
147 // 2 bytes for the varint field (id: 2) of the 1st nested message 149 // 2 bytes for the varint field (id: 2) of the 1st nested message
148 // 6 bytes for the premable of the 2nd nested message 150 // 6 bytes for the premable of the 2nd nested message
149 // 2 bytes for the varint field (id: 4) of the 2nd nested message. 151 // 2 bytes for the varint field (id: 4) of the 2nd nested message.
(...skipping 13 matching lines...) Expand all
163 ASSERT_EQ("8A0882808000", GetNextSerializedBytes(6)); 165 ASSERT_EQ("8A0882808000", GetNextSerializedBytes(6));
164 ASSERT_EQ("2002", GetNextSerializedBytes(2)); 166 ASSERT_EQ("2002", GetNextSerializedBytes(2));
165 167
166 ASSERT_EQ("2803", GetNextSerializedBytes(2)); 168 ASSERT_EQ("2803", GetNextSerializedBytes(2));
167 } 169 }
168 170
169 // Checks that the size field of root and nested messages is properly written 171 // Checks that the size field of root and nested messages is properly written
170 // on finalization. 172 // on finalization.
171 TEST_F(ProtoZeroMessageTest, BackfillSizeOnFinalization) { 173 TEST_F(ProtoZeroMessageTest, BackfillSizeOnFinalization) {
172 ProtoZeroMessage* root_msg = NewMessage(); 174 ProtoZeroMessage* root_msg = NewMessage();
173 uint8_t root_msg_size[proto::kMessageLengthFieldSize]; 175 uint8_t root_msg_size[proto::kMessageLengthFieldSize] = {};
174 root_msg->set_size_field( 176 root_msg->set_size_field(
175 {&root_msg_size[0], &root_msg_size[proto::kMessageLengthFieldSize]}); 177 {&root_msg_size[0], &root_msg_size[proto::kMessageLengthFieldSize]});
176 root_msg->AppendVarIntU32(1, 0x42); 178 root_msg->AppendVarIntU32(1, 0x42);
177 179
178 FakeMessage* nested_msg_1 = root_msg->BeginNestedMessage<FakeMessage>(2); 180 FakeChildMessage* nested_msg_1 =
181 root_msg->BeginNestedMessage<FakeChildMessage>(2);
179 nested_msg_1->AppendVarIntU32(3, 0x43); 182 nested_msg_1->AppendVarIntU32(3, 0x43);
180 183
181 FakeMessage* nested_msg_2 = nested_msg_1->BeginNestedMessage<FakeMessage>(4); 184 FakeChildMessage* nested_msg_2 =
185 nested_msg_1->BeginNestedMessage<FakeChildMessage>(4);
182 uint8_t buf200[200]; 186 uint8_t buf200[200];
183 memset(buf200, 0x42, sizeof(buf200)); 187 memset(buf200, 0x42, sizeof(buf200));
184 nested_msg_2->AppendBytes(5, buf200, sizeof(buf200)); 188 nested_msg_2->AppendBytes(5, buf200, sizeof(buf200));
185 189
186 root_msg->inc_size_already_written(6); 190 root_msg->inc_size_already_written(6);
187 191
188 // The value returned by Finalize() should be == the full size of |root_msg|. 192 // The value returned by Finalize() should be == the full size of |root_msg|.
189 EXPECT_EQ(217u, root_msg->Finalize()); 193 EXPECT_EQ(217u, root_msg->Finalize());
190 EXPECT_EQ(217u, GetNumSerializedBytes()); 194 EXPECT_EQ(217u, GetNumSerializedBytes());
191 195
(...skipping 27 matching lines...) Expand all
219 223
220 // The main point of this test is to stress the code paths and test for 224 // The main point of this test is to stress the code paths and test for
221 // unexpected crashes of the production code. The actual serialization is 225 // unexpected crashes of the production code. The actual serialization is
222 // already covered in the other text fixtures. Keeping just a final smoke test 226 // already covered in the other text fixtures. Keeping just a final smoke test
223 // here on the full buffer hash. 227 // here on the full buffer hash.
224 std::string full_buf = GetNextSerializedBytes(GetNumSerializedBytes()); 228 std::string full_buf = GetNextSerializedBytes(GetNumSerializedBytes());
225 uint32_t buf_hash = base::SuperFastHash(full_buf.data(), full_buf.size()); 229 uint32_t buf_hash = base::SuperFastHash(full_buf.data(), full_buf.size());
226 EXPECT_EQ(0x14BC1BA3u, buf_hash); 230 EXPECT_EQ(0x14BC1BA3u, buf_hash);
227 } 231 }
228 232
233 TEST_F(ProtoZeroMessageTest, MessageHandle) {
234 FakeRootMessage* msg1 = NewMessage();
235 FakeRootMessage* msg2 = NewMessage();
236 FakeRootMessage* msg3 = NewMessage();
237 FakeRootMessage* ignored_msg = NewMessage();
238 uint8_t msg1_size[proto::kMessageLengthFieldSize] = {};
239 uint8_t msg2_size[proto::kMessageLengthFieldSize] = {};
240 uint8_t msg3_size[proto::kMessageLengthFieldSize] = {};
241 msg1->set_size_field(
242 {&msg1_size[0], &msg1_size[proto::kMessageLengthFieldSize]});
243 msg2->set_size_field(
244 {&msg2_size[0], &msg2_size[proto::kMessageLengthFieldSize]});
245 msg3->set_size_field(
246 {&msg3_size[0], &msg3_size[proto::kMessageLengthFieldSize]});
247
248 // Test that the handle going out of scope causes the finalization of the
249 // target message.
250 {
251 ProtoZeroMessageHandle<FakeRootMessage> handle1(msg1);
252 handle1->AppendBytes(1 /* field_id */, kTestBytes, 1 /* size */);
253 ASSERT_EQ(0u, msg1_size[0]);
254 }
255 ASSERT_EQ(0x83u, msg1_size[0]);
256
257 // Test that the handle can be late initialized.
258 ProtoZeroMessageHandle<FakeRootMessage> handle2(ignored_msg);
259 handle2 = ProtoZeroMessageHandle<FakeRootMessage>(msg2);
260 handle2->AppendBytes(1 /* field_id */, kTestBytes, 2 /* size */);
261 ASSERT_EQ(0u, msg2_size[0]); // |msg2| should not be finalized yet.
262
263 // Test that std::move works and does NOT cause finalization of the moved
264 // message.
265 ProtoZeroMessageHandle<FakeRootMessage> handle_swp(ignored_msg);
266 handle_swp = std::move(handle2);
267 ASSERT_EQ(0u, msg2_size[0]); // msg2 should be NOT finalized yet.
268 handle_swp->AppendBytes(2 /* field_id */, kTestBytes, 3 /* size */);
269
270 ProtoZeroMessageHandle<FakeRootMessage> handle3(msg3);
271 handle3->AppendBytes(1 /* field_id */, kTestBytes, 4 /* size */);
272 ASSERT_EQ(0u, msg3_size[0]); // msg2 should be NOT finalized yet.
273
274 // Both |handle3| and |handle_swp| point to a valid message (respectively,
275 // |msg3| and |msg2|). Now move |handle3| into |handle_swp|.
276 handle_swp = std::move(handle3);
277 ASSERT_EQ(0x89u, msg2_size[0]); // |msg2| should be finalized at this point.
278
279 // At this point writing into handle_swp should actually write into |msg3|.
280 ASSERT_EQ(msg3, &*handle_swp);
281 handle_swp->AppendBytes(2 /* field_id */, kTestBytes, 8 /* size */);
282 ProtoZeroMessageHandle<FakeRootMessage> another_handle(ignored_msg);
283 handle_swp = std::move(another_handle);
284 ASSERT_EQ(0x90u, msg3_size[0]); // |msg3| should be finalized at this point.
285
286 #if DCHECK_IS_ON()
287 // In developer builds w/ DCHECK on a finalized message should invalidate the
288 // handle, in order to early catch bugs in the client code.
289 FakeRootMessage* msg4 = NewMessage();
290 ProtoZeroMessageHandle<FakeRootMessage> handle4(msg4);
291 ASSERT_EQ(msg4, &*handle4);
292 msg4->Finalize();
293 ASSERT_EQ(nullptr, &*handle4);
294 #endif
295
296 // Test also the behavior of handle with non-root (nested) messages.
297
298 ContiguousMemoryRange size_msg_2;
299 {
300 auto* nested_msg_1 = NewMessage()->BeginNestedMessage<FakeChildMessage>(3);
301 ProtoZeroMessageHandle<FakeChildMessage> child_handle_1(nested_msg_1);
302 ContiguousMemoryRange size_msg_1 = nested_msg_1->size_field();
303 memset(size_msg_1.begin, 0, size_msg_1.size());
304 child_handle_1->AppendVarIntU32(1, 0x11);
305
306 auto* nested_msg_2 = NewMessage()->BeginNestedMessage<FakeChildMessage>(2);
307 size_msg_2 = nested_msg_2->size_field();
308 memset(size_msg_2.begin, 0, size_msg_2.size());
309 ProtoZeroMessageHandle<FakeChildMessage> child_handle_2(nested_msg_2);
310 child_handle_2->AppendVarIntU32(2, 0xFF);
311
312 // |nested_msg_1| should not be finalized yet.
313 ASSERT_EQ(0u, size_msg_1.begin[0]);
314
315 // This move should cause |nested_msg_1| to be finalized, but not
316 // |nested_msg_2|, which will be finalized only after the current scope.
317 child_handle_1 = std::move(child_handle_2);
318 ASSERT_EQ(0x82u, size_msg_1.begin[0]);
319 ASSERT_EQ(0u, size_msg_2.begin[0]);
320 }
321 ASSERT_EQ(0x83u, size_msg_2.begin[0]);
322 }
323
229 } // namespace v2 324 } // namespace v2
230 } // namespace tracing 325 } // namespace tracing
OLDNEW
« no previous file with comments | « components/tracing/core/proto_zero_message_handle.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698