xref: /aosp_15_r20/external/perfetto/src/tracing/service/trace_buffer_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 <string.h>
18 
19 #include <initializer_list>
20 #include <random>
21 #include <sstream>
22 #include <vector>
23 
24 #include "perfetto/ext/base/utils.h"
25 #include "perfetto/ext/tracing/core/basic_types.h"
26 #include "perfetto/ext/tracing/core/client_identity.h"
27 #include "perfetto/ext/tracing/core/shared_memory_abi.h"
28 #include "perfetto/ext/tracing/core/trace_packet.h"
29 #include "perfetto/protozero/proto_utils.h"
30 #include "src/base/test/vm_test_utils.h"
31 #include "src/tracing/service/trace_buffer.h"
32 #include "src/tracing/test/fake_packet.h"
33 #include "test/gtest_and_gmock.h"
34 
35 namespace perfetto {
36 
37 using ::testing::ContainerEq;
38 using ::testing::ElementsAre;
39 using ::testing::IsEmpty;
40 
41 class TraceBufferTest : public testing::Test {
42  public:
43   using SequenceIterator = TraceBuffer::SequenceIterator;
44   using ChunkMetaKey = TraceBuffer::ChunkMeta::Key;
45   using ChunkRecord = TraceBuffer::ChunkRecord;
46 
47   static constexpr uint8_t kContFromPrevChunk =
48       SharedMemoryABI::ChunkHeader::kFirstPacketContinuesFromPrevChunk;
49   static constexpr uint8_t kContOnNextChunk =
50       SharedMemoryABI::ChunkHeader::kLastPacketContinuesOnNextChunk;
51   static constexpr uint8_t kChunkNeedsPatching =
52       SharedMemoryABI::ChunkHeader::kChunkNeedsPatching;
53 
TearDown()54   void TearDown() override {
55     // Test that the used_size() logic works and that all the data after that
56     // is zero-filled.
57     if (trace_buffer_) {
58       const size_t used_size = trace_buffer_->used_size();
59       ASSERT_LE(used_size, trace_buffer_->size());
60       trace_buffer_->EnsureCommitted(trace_buffer_->size());
61       bool zero_padded = true;
62       for (size_t i = used_size; i < trace_buffer_->size(); ++i) {
63         bool is_zero = static_cast<char*>(trace_buffer_->data_.Get())[i] == 0;
64         zero_padded = zero_padded && is_zero;
65       }
66       ASSERT_TRUE(zero_padded);
67     }
68   }
69 
CreateChunk(ProducerID p,WriterID w,ChunkID c)70   FakeChunk CreateChunk(ProducerID p, WriterID w, ChunkID c) {
71     return FakeChunk(trace_buffer_.get(), p, w, c);
72   }
73 
ResetBuffer(size_t size_,TraceBuffer::OverwritePolicy policy=TraceBuffer::kOverwrite)74   void ResetBuffer(
75       size_t size_,
76       TraceBuffer::OverwritePolicy policy = TraceBuffer::kOverwrite) {
77     trace_buffer_ = TraceBuffer::Create(size_, policy);
78     ASSERT_TRUE(trace_buffer_);
79   }
80 
TryPatchChunkContents(ProducerID p,WriterID w,ChunkID c,std::vector<TraceBuffer::Patch> patches,bool other_patches_pending=false)81   bool TryPatchChunkContents(ProducerID p,
82                              WriterID w,
83                              ChunkID c,
84                              std::vector<TraceBuffer::Patch> patches,
85                              bool other_patches_pending = false) {
86     return trace_buffer_->TryPatchChunkContents(
87         p, w, c, patches.data(), patches.size(), other_patches_pending);
88   }
89 
ReadPacket(const std::unique_ptr<TraceBuffer> & buf,TraceBuffer::PacketSequenceProperties * sequence_properties=nullptr,bool * previous_packet_dropped=nullptr)90   static std::vector<FakePacketFragment> ReadPacket(
91       const std::unique_ptr<TraceBuffer>& buf,
92       TraceBuffer::PacketSequenceProperties* sequence_properties = nullptr,
93       bool* previous_packet_dropped = nullptr) {
94     std::vector<FakePacketFragment> fragments;
95     TracePacket packet;
96     TraceBuffer::PacketSequenceProperties ignored_sequence_properties{};
97     bool ignored_previous_packet_dropped;
98     if (!buf->ReadNextTracePacket(
99             &packet,
100             sequence_properties ? sequence_properties
101                                 : &ignored_sequence_properties,
102             previous_packet_dropped ? previous_packet_dropped
103                                     : &ignored_previous_packet_dropped)) {
104       return fragments;
105     }
106     for (const Slice& slice : packet.slices())
107       fragments.emplace_back(slice.start, slice.size);
108     return fragments;
109   }
110 
ReadPacket(TraceBuffer::PacketSequenceProperties * sequence_properties=nullptr,bool * previous_packet_dropped=nullptr)111   std::vector<FakePacketFragment> ReadPacket(
112       TraceBuffer::PacketSequenceProperties* sequence_properties = nullptr,
113       bool* previous_packet_dropped = nullptr) {
114     return ReadPacket(trace_buffer_, sequence_properties,
115                       previous_packet_dropped);
116   }
117 
AppendChunks(std::initializer_list<std::tuple<ProducerID,WriterID,ChunkID>> chunks)118   void AppendChunks(
119       std::initializer_list<std::tuple<ProducerID, WriterID, ChunkID>> chunks) {
120     for (const auto& c : chunks) {
121       char seed =
122           static_cast<char>(std::get<0>(c) + std::get<1>(c) + std::get<2>(c));
123       CreateChunk(std::get<0>(c), std::get<1>(c), std::get<2>(c))
124           .AddPacket(4, seed)
125           .CopyIntoTraceBuffer();
126     }
127   }
128 
IteratorSeqEq(ProducerID p,WriterID w,std::initializer_list<ChunkID> chunk_ids)129   bool IteratorSeqEq(ProducerID p,
130                      WriterID w,
131                      std::initializer_list<ChunkID> chunk_ids) {
132     std::stringstream expected_seq;
133     for (const auto& c : chunk_ids)
134       expected_seq << "{" << p << "," << w << "," << c << "},";
135 
136     std::stringstream actual_seq;
137     for (auto it = GetReadIterForSequence(p, w); it.is_valid(); it.MoveNext()) {
138       actual_seq << "{" << it.producer_id() << "," << it.writer_id() << ","
139                  << it.chunk_id() << "},";
140     }
141     std::string expected_seq_str = expected_seq.str();
142     std::string actual_seq_str = actual_seq.str();
143     EXPECT_EQ(expected_seq_str, actual_seq_str);
144     return expected_seq_str == actual_seq_str;
145   }
146 
GetReadIterForSequence(ProducerID p,WriterID w)147   SequenceIterator GetReadIterForSequence(ProducerID p, WriterID w) {
148     TraceBuffer::ChunkMeta::Key key(p, w, 0);
149     return trace_buffer_->GetReadIterForSequence(
150         trace_buffer_->index_.lower_bound(key));
151   }
152 
SuppressClientDchecksForTesting()153   void SuppressClientDchecksForTesting() {
154     trace_buffer_->suppress_client_dchecks_for_testing_ = true;
155   }
156 
GetIndex()157   std::vector<ChunkMetaKey> GetIndex() {
158     std::vector<ChunkMetaKey> keys;
159     keys.reserve(trace_buffer_->index_.size());
160     for (const auto& it : trace_buffer_->index_)
161       keys.push_back(it.first);
162     return keys;
163   }
164 
GetBufData(const TraceBuffer & buf)165   uint8_t* GetBufData(const TraceBuffer& buf) { return buf.begin(); }
trace_buffer()166   TraceBuffer* trace_buffer() { return trace_buffer_.get(); }
size_to_end()167   size_t size_to_end() { return trace_buffer_->size_to_end(); }
168 
169  private:
170   std::unique_ptr<TraceBuffer> trace_buffer_;
171 };
172 
173 // ----------------------
174 // Main TraceBuffer tests
175 // ----------------------
176 
177 // Note for the test code: remember that the resulting size of a chunk is:
178 // SUM(packets) + 16 (that is sizeof(ChunkRecord)).
179 // Also remember that chunks are rounded up to 16. So, unless we are testing the
180 // rounding logic, might be a good idea to create chunks of that size.
181 
TEST_F(TraceBufferTest,ReadWrite_EmptyBuffer)182 TEST_F(TraceBufferTest, ReadWrite_EmptyBuffer) {
183   ResetBuffer(4096);
184   trace_buffer()->BeginRead();
185   ASSERT_THAT(ReadPacket(), IsEmpty());
186 }
187 
188 // On each iteration writes a fixed-size chunk and reads it back.
TEST_F(TraceBufferTest,ReadWrite_Simple)189 TEST_F(TraceBufferTest, ReadWrite_Simple) {
190   ResetBuffer(64 * 1024);
191   for (ChunkID chunk_id = 0; chunk_id < 1000; chunk_id++) {
192     char seed = static_cast<char>(chunk_id);
193     CreateChunk(ProducerID(1), WriterID(1), chunk_id)
194         .AddPacket(42, seed)
195         .CopyIntoTraceBuffer();
196     trace_buffer()->BeginRead();
197     ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(42, seed)));
198     ASSERT_THAT(ReadPacket(), IsEmpty());
199     EXPECT_EQ(chunk_id + 1u, trace_buffer()->stats().chunks_written());
200     EXPECT_EQ(trace_buffer()->stats().chunks_written(),
201               trace_buffer()->stats().chunks_read());
202     EXPECT_LT(0u, trace_buffer()->stats().bytes_written());
203     EXPECT_EQ(trace_buffer()->stats().bytes_written(),
204               trace_buffer()->stats().bytes_read());
205     EXPECT_EQ(0u, trace_buffer()->stats().padding_bytes_written());
206     EXPECT_EQ(0u, trace_buffer()->stats().padding_bytes_cleared());
207   }
208 }
209 
TEST_F(TraceBufferTest,ReadWrite_OneChunkPerWriter)210 TEST_F(TraceBufferTest, ReadWrite_OneChunkPerWriter) {
211   for (int8_t num_writers = 1; num_writers <= 10; num_writers++) {
212     ResetBuffer(4096);
213     for (char i = 1; i <= num_writers; i++) {
214       ASSERT_EQ(32u, CreateChunk(ProducerID(i), WriterID(i), ChunkID(i))
215                          .AddPacket(32 - 16, i)
216                          .CopyIntoTraceBuffer());
217     }
218 
219     // The expected read sequence now is: c3, c4, c5.
220     trace_buffer()->BeginRead();
221     for (char i = 1; i <= num_writers; i++)
222       ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(32 - 16, i)));
223     ASSERT_THAT(ReadPacket(), IsEmpty());
224   }  // for(num_writers)
225 }
226 
227 // Writes chunk that up filling the buffer precisely until the end, like this:
228 // [ c0: 512 ][ c1: 512 ][ c2: 1024 ][ c3: 2048 ]
229 // | ---------------- 4k buffer --------------- |
TEST_F(TraceBufferTest,ReadWrite_FillTillEnd)230 TEST_F(TraceBufferTest, ReadWrite_FillTillEnd) {
231   ResetBuffer(4096);
232   for (int i = 0; i < 3; i++) {
233     ASSERT_EQ(512u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(i * 4))
234                         .AddPacket(512 - 16, 'a')
235                         .CopyIntoTraceBuffer());
236     ASSERT_EQ(512u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(i * 4 + 1))
237                         .AddPacket(512 - 16, 'b')
238                         .CopyIntoTraceBuffer());
239     ASSERT_EQ(1024u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(i * 4 + 2))
240                          .AddPacket(1024 - 16, 'c')
241                          .CopyIntoTraceBuffer());
242     ASSERT_EQ(2048u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(i * 4 + 3))
243                          .AddPacket(2048 - 16, 'd')
244                          .CopyIntoTraceBuffer());
245 
246     // At this point the write pointer should have been reset at the beginning.
247     ASSERT_EQ(4096u, size_to_end());
248 
249     trace_buffer()->BeginRead();
250     ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(512 - 16, 'a')));
251     ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(512 - 16, 'b')));
252     ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(1024 - 16, 'c')));
253     ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(2048 - 16, 'd')));
254     ASSERT_THAT(ReadPacket(), IsEmpty());
255   }
256 }
257 
258 // Similar to the above, but this time leaves some gap at the end and then
259 // tries to add a chunk that doesn't fit to exercise the padding-at-end logic.
260 // Initial condition:
261 // [ c0: 128 ][ c1: 256 ][ c2: 512   ][ c3: 1024 ][ c4: 2048 ]{ 128 padding }
262 // | ------------------------------- 4k buffer ------------------------------ |
263 //
264 // At this point we try to insert a 512 Bytes chunk (c5). The result should be:
265 // [ c5: 512              ]{ padding }[c3: 1024 ][ c4: 2048 ]{ 128 padding }
266 // | ------------------------------- 4k buffer ------------------------------ |
TEST_F(TraceBufferTest,ReadWrite_Padding)267 TEST_F(TraceBufferTest, ReadWrite_Padding) {
268   ResetBuffer(4096);
269   ASSERT_EQ(128u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
270                       .AddPacket(128 - 16, 'a')
271                       .CopyIntoTraceBuffer());
272   ASSERT_EQ(256u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
273                       .AddPacket(256 - 16, 'b')
274                       .CopyIntoTraceBuffer());
275   ASSERT_EQ(512u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
276                       .AddPacket(512 - 16, 'c')
277                       .CopyIntoTraceBuffer());
278   ASSERT_EQ(1024u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(3))
279                        .AddPacket(1024 - 16, 'd')
280                        .CopyIntoTraceBuffer());
281   ASSERT_EQ(2048u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(4))
282                        .AddPacket(2048 - 16, 'e')
283                        .CopyIntoTraceBuffer());
284 
285   // Now write c5 that will cause wrapping + padding.
286   ASSERT_EQ(128u, size_to_end());
287   ASSERT_EQ(512u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(5))
288                       .AddPacket(512 - 16, 'f')
289                       .CopyIntoTraceBuffer());
290   ASSERT_EQ(4096u - 512, size_to_end());
291 
292   // The expected read sequence now is: c3, c4, c5.
293   trace_buffer()->BeginRead();
294   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(1024 - 16, 'd')));
295   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(2048 - 16, 'e')));
296   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(512 - 16, 'f')));
297   ASSERT_THAT(ReadPacket(), IsEmpty());
298 
299   EXPECT_EQ(6u, trace_buffer()->stats().chunks_written());
300   EXPECT_EQ(3u, trace_buffer()->stats().chunks_overwritten());
301   EXPECT_EQ(3u, trace_buffer()->stats().chunks_read());
302   EXPECT_EQ(4480u, trace_buffer()->stats().bytes_written());
303   EXPECT_EQ(896u, trace_buffer()->stats().bytes_overwritten());
304   EXPECT_EQ(3584u, trace_buffer()->stats().bytes_read());
305   EXPECT_EQ(512u, trace_buffer()->stats().padding_bytes_written());
306   EXPECT_EQ(0u, trace_buffer()->stats().padding_bytes_cleared());
307 
308   // Adding another chunk should clear some of the padding.
309   ASSERT_EQ(128u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(6))
310                       .AddPacket(128 - 16, 'g')
311                       .CopyIntoTraceBuffer());
312   EXPECT_EQ(384u, trace_buffer()->stats().padding_bytes_cleared());
313 }
314 
315 // Like ReadWrite_Padding, but this time the padding introduced is the minimum
316 // allowed (16 bytes). This is to exercise edge cases in the padding logic.
317 // [c0: 2048               ][c1: 1024         ][c2: 1008       ][c3: 16]
318 // [c4: 2032            ][c5: 1040                ][c6 :16][c7: 1080   ]
TEST_F(TraceBufferTest,ReadWrite_MinimalPadding)319 TEST_F(TraceBufferTest, ReadWrite_MinimalPadding) {
320   ResetBuffer(4096);
321 
322   ASSERT_EQ(2048u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
323                        .AddPacket(2048 - 16, 'a')
324                        .CopyIntoTraceBuffer());
325   ASSERT_EQ(1024u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
326                        .AddPacket(1024 - 16, 'b')
327                        .CopyIntoTraceBuffer());
328   ASSERT_EQ(1008u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
329                        .AddPacket(1008 - 16, 'c')
330                        .CopyIntoTraceBuffer());
331   ASSERT_EQ(16u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(3))
332                      .CopyIntoTraceBuffer());
333 
334   ASSERT_EQ(4096u, size_to_end());
335 
336   ASSERT_EQ(2032u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(4))
337                        .AddPacket(2032 - 16, 'd')
338                        .CopyIntoTraceBuffer());
339   ASSERT_EQ(1040u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(5))
340                        .AddPacket(1040 - 16, 'e')
341                        .CopyIntoTraceBuffer());
342   ASSERT_EQ(16u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(6))
343                      .CopyIntoTraceBuffer());
344   ASSERT_EQ(1008u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(7))
345                        .AddPacket(1008 - 16, 'f')
346                        .CopyIntoTraceBuffer());
347 
348   ASSERT_EQ(4096u, size_to_end());
349 
350   // The expected read sequence now is: c3, c4, c5.
351   trace_buffer()->BeginRead();
352   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(2032 - 16, 'd')));
353   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(1040 - 16, 'e')));
354   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(1008 - 16, 'f')));
355   for (int i = 0; i < 3; i++)
356     ASSERT_THAT(ReadPacket(), IsEmpty());
357 }
358 
TEST_F(TraceBufferTest,ReadWrite_RandomChunksNoWrapping)359 TEST_F(TraceBufferTest, ReadWrite_RandomChunksNoWrapping) {
360   for (unsigned int seed = 1; seed <= 32; seed++) {
361     std::minstd_rand0 rnd_engine(seed);
362     ResetBuffer(4096 * (1 + rnd_engine() % 32));
363     std::uniform_int_distribution<size_t> size_dist(18, 4096);
364     std::uniform_int_distribution<ProducerID> prod_dist(1, kMaxProducerID);
365     std::uniform_int_distribution<WriterID> wri_dist(1, kMaxWriterID);
366     ChunkID chunk_id = 0;
367     std::map<std::tuple<ProducerID, WriterID, ChunkID>, size_t> expected_chunks;
368     for (;;) {
369       const size_t chunk_size = size_dist(rnd_engine);
370       if (base::AlignUp<16>(chunk_size) >= size_to_end())
371         break;
372       ProducerID p = prod_dist(rnd_engine);
373       WriterID w = wri_dist(rnd_engine);
374       ChunkID c = chunk_id++;
375       expected_chunks.emplace(std::make_tuple(p, w, c), chunk_size);
376       ASSERT_EQ(chunk_size,
377                 CreateChunk(p, w, c)
378                     .AddPacket(chunk_size - 16, static_cast<char>(chunk_size))
379                     .CopyIntoTraceBuffer());
380     }  // for(;;)
381     trace_buffer()->BeginRead();
382     for (const auto& it : expected_chunks) {
383       const size_t chunk_size = it.second;
384       ASSERT_THAT(ReadPacket(),
385                   ElementsAre(FakePacketFragment(
386                       chunk_size - 16, static_cast<char>(chunk_size))));
387     }
388     ASSERT_THAT(ReadPacket(), IsEmpty());
389   }
390 }
391 
392 // Tests the case of writing a chunk that leaves just sizeof(ChunkRecord) at
393 // the end of the buffer.
TEST_F(TraceBufferTest,ReadWrite_WrappingCases)394 TEST_F(TraceBufferTest, ReadWrite_WrappingCases) {
395   ResetBuffer(4096);
396   ASSERT_EQ(4080u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
397                        .AddPacket(4080 - 16, 'a')
398                        .CopyIntoTraceBuffer());
399   trace_buffer()->BeginRead();
400   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4080 - 16, 'a')));
401   ASSERT_THAT(ReadPacket(), IsEmpty());
402 
403   ASSERT_EQ(16u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
404                      .CopyIntoTraceBuffer());
405   ASSERT_EQ(2048u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
406                        .AddPacket(2048 - 16, 'b')
407                        .CopyIntoTraceBuffer());
408   ASSERT_EQ(2048u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(3))
409                        .AddPacket(2048 - 16, 'c')
410                        .CopyIntoTraceBuffer());
411   trace_buffer()->BeginRead();
412   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(2048 - 16, 'b')));
413   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(2048 - 16, 'c')));
414   ASSERT_THAT(ReadPacket(), IsEmpty());
415 }
416 
417 // Tests that when records are removed when adding padding at the end because
418 // there is no space left. The scenario is the following:
419 // Initial condition: [ c0: 2048 ][ c1: 2048 ]
420 // 2nd iteration:     [ c2: 2048] <-- write pointer is here
421 // At this point we try to add a 3072 bytes chunk. It won't fit because the
422 // space left till the end is just 2048 bytes. At this point we expect that a
423 // padding record is added in place of c1, and c1 is removed from the index.
424 // Final situation:   [ c3: 3072     ][ PAD ]
TEST_F(TraceBufferTest,ReadWrite_PaddingAtEndUpdatesIndex)425 TEST_F(TraceBufferTest, ReadWrite_PaddingAtEndUpdatesIndex) {
426   ResetBuffer(4096);
427   // Setup initial condition: [ c0: 2048 ][ c1: 2048 ]
428   ASSERT_EQ(2048u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
429                        .AddPacket(2048 - 16, 'a')
430                        .CopyIntoTraceBuffer());
431   ASSERT_EQ(2048u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
432                        .AddPacket(2048 - 16, 'b')
433                        .CopyIntoTraceBuffer());
434   ASSERT_THAT(GetIndex(),
435               ElementsAre(ChunkMetaKey(1, 1, 0), ChunkMetaKey(1, 1, 1)));
436 
437   // Wrap and get to this: [ c2: 2048] <-- write pointer is here
438   ASSERT_EQ(2048u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
439                        .AddPacket(2048 - 16, 'c')
440                        .CopyIntoTraceBuffer());
441   ASSERT_EQ(2048u, size_to_end());
442   ASSERT_THAT(GetIndex(),
443               ElementsAre(ChunkMetaKey(1, 1, 1), ChunkMetaKey(1, 1, 2)));
444 
445   // Force wrap because of lack of space and get: [ c3: 3072     ][ PAD ].
446   ASSERT_EQ(3072u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(3))
447                        .AddPacket(3072 - 16, 'd')
448                        .CopyIntoTraceBuffer());
449   ASSERT_THAT(GetIndex(), ElementsAre(ChunkMetaKey(1, 1, 3)));
450 
451   trace_buffer()->BeginRead();
452   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(3072 - 16, 'd')));
453   ASSERT_THAT(ReadPacket(), IsEmpty());
454 }
455 
456 // Similar to ReadWrite_PaddingAtEndUpdatesIndex but makes it so that the
457 // various chunks don't perfectly align when wrapping.
TEST_F(TraceBufferTest,ReadWrite_PaddingAtEndUpdatesIndexMisaligned)458 TEST_F(TraceBufferTest, ReadWrite_PaddingAtEndUpdatesIndexMisaligned) {
459   ResetBuffer(4096);
460 
461   // [c0: 512][c1: 512][c2: 512][c3: 512][c4: 512][c5: 512][c6: 512][c7: 512]
462   for (char i = 0; i < 8; i++) {
463     ASSERT_EQ(512u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(i))
464                         .AddPacket(512 - 16, 'a' + i)
465                         .CopyIntoTraceBuffer());
466   }
467   ASSERT_EQ(8u, GetIndex().size());
468 
469   // [c8: 2080..........................][PAD][c5: 512][c6: 512][c7: 512]
470   //                                     ^ write pointer is here.
471   ASSERT_EQ(2080u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(8))
472                        .AddPacket(2080 - 16, 'i')
473                        .CopyIntoTraceBuffer());
474   ASSERT_EQ(2016u, size_to_end());
475   ASSERT_THAT(GetIndex(),
476               ElementsAre(ChunkMetaKey(1, 1, 5), ChunkMetaKey(1, 1, 6),
477                           ChunkMetaKey(1, 1, 7), ChunkMetaKey(1, 1, 8)));
478 
479   // [ c9: 3104....................................][ PAD...............].
480   ASSERT_EQ(3104u, CreateChunk(ProducerID(1), WriterID(1), ChunkID(9))
481                        .AddPacket(3104 - 16, 'j')
482                        .CopyIntoTraceBuffer());
483   ASSERT_THAT(GetIndex(), ElementsAre(ChunkMetaKey(1, 1, 9)));
484 
485   trace_buffer()->BeginRead();
486   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(3104u - 16, 'j')));
487   ASSERT_THAT(ReadPacket(), IsEmpty());
488 }
489 
490 // Verify that empty packets are skipped.
TEST_F(TraceBufferTest,ReadWrite_EmptyPacket)491 TEST_F(TraceBufferTest, ReadWrite_EmptyPacket) {
492   ResetBuffer(4096);
493   CreateChunk(ProducerID(1), WriterID(1), 0)
494       .AddPacket(42, 1)
495       .AddPacket(1, 2)
496       .AddPacket(42, 3)
497       .CopyIntoTraceBuffer();
498 
499   trace_buffer()->BeginRead();
500   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(42, 1)));
501   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(42, 3)));
502   ASSERT_THAT(ReadPacket(), IsEmpty());
503 
504   EXPECT_EQ(0u, trace_buffer()->stats().abi_violations());
505 }
506 
507 // --------------------------------------
508 // Fragments stitching and skipping logic
509 // --------------------------------------
510 
TEST_F(TraceBufferTest,Fragments_Simple)511 TEST_F(TraceBufferTest, Fragments_Simple) {
512   ResetBuffer(4096);
513   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
514       .AddPacket(10, 'a', kContFromPrevChunk)
515       .AddPacket(20, 'b')
516       .AddPacket(30, 'c')
517       .AddPacket(10, 'd', kContOnNextChunk)
518       .CopyIntoTraceBuffer();
519   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
520       .AddPacket(20, 'e', kContFromPrevChunk)
521       .AddPacket(30, 'f')
522       .CopyIntoTraceBuffer();
523 
524   trace_buffer()->BeginRead();
525   // The (10, 'a') entry should be skipped because we don't have provided the
526   // previous chunk, hence should be treated as a data loss.
527   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'b')));
528   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'c')));
529   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'd'),
530                                         FakePacketFragment(20, 'e')));
531   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'f')));
532   ASSERT_THAT(ReadPacket(), IsEmpty());
533 }
534 
TEST_F(TraceBufferTest,Fragments_EdgeCases)535 TEST_F(TraceBufferTest, Fragments_EdgeCases) {
536   ResetBuffer(4096);
537   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
538       .AddPacket(2, 'a', kContFromPrevChunk)
539       .CopyIntoTraceBuffer();
540   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
541       .AddPacket(2, 'b', kContOnNextChunk)
542       .CopyIntoTraceBuffer();
543   trace_buffer()->BeginRead();
544   ASSERT_THAT(ReadPacket(), IsEmpty());
545 
546   // Now add the missing fragment.
547   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
548       .AddPacket(2, 'c', kContFromPrevChunk)
549       .CopyIntoTraceBuffer();
550   trace_buffer()->BeginRead();
551   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(2, 'b'),
552                                         FakePacketFragment(2, 'c')));
553   ASSERT_THAT(ReadPacket(), IsEmpty());
554 }
555 
556 // The following tests verify that chunks received out-of-order are read in the
557 // correct order.
558 //
559 // Fragment order {0,2,1} for sequence {1,1}, without fragmenting packets.
TEST_F(TraceBufferTest,Fragments_OutOfOrderLastChunkIsMiddle)560 TEST_F(TraceBufferTest, Fragments_OutOfOrderLastChunkIsMiddle) {
561   ResetBuffer(4096);
562   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
563       .AddPacket(10, 'a')
564       .CopyIntoTraceBuffer();
565   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
566       .AddPacket(30, 'c')
567       .CopyIntoTraceBuffer();
568   EXPECT_EQ(0u, trace_buffer()->stats().chunks_committed_out_of_order());
569   trace_buffer()->BeginRead();
570   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'a')));
571   ASSERT_THAT(ReadPacket(), IsEmpty());
572 
573   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
574       .AddPacket(20, 'b')
575       .CopyIntoTraceBuffer();
576   EXPECT_EQ(1u, trace_buffer()->stats().chunks_committed_out_of_order());
577   trace_buffer()->BeginRead();
578   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'b')));
579   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'c')));
580   ASSERT_THAT(ReadPacket(), IsEmpty());
581 }
582 
583 // Fragment order {0,2,1} for sequence {1,1}, with fragmenting packets.
TEST_F(TraceBufferTest,Fragments_OutOfOrderLastChunkIsMiddleFragmentation)584 TEST_F(TraceBufferTest, Fragments_OutOfOrderLastChunkIsMiddleFragmentation) {
585   ResetBuffer(4096);
586   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
587       .AddPacket(10, 'a', kContOnNextChunk)
588       .CopyIntoTraceBuffer();
589   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
590       .AddPacket(30, 'c', kContFromPrevChunk)
591       .CopyIntoTraceBuffer();
592   trace_buffer()->BeginRead();
593   ASSERT_THAT(ReadPacket(), IsEmpty());
594 
595   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
596       .AddPacket(20, 'b', kContFromPrevChunk | kContOnNextChunk)
597       .CopyIntoTraceBuffer();
598   trace_buffer()->BeginRead();
599   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'a'),
600                                         FakePacketFragment(20, 'b'),
601                                         FakePacketFragment(30, 'c')));
602   ASSERT_THAT(ReadPacket(), IsEmpty());
603 }
604 
605 // Fragment order {0,2,1,3} for sequence {1,1}, with fragmenting packets. Also
606 // verifies that another sequence isn't broken.
TEST_F(TraceBufferTest,Fragments_OutOfOrderLastChunkIsMaxFragmentation)607 TEST_F(TraceBufferTest, Fragments_OutOfOrderLastChunkIsMaxFragmentation) {
608   ResetBuffer(4096);
609   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
610       .AddPacket(10, 'a', kContOnNextChunk)
611       .CopyIntoTraceBuffer();
612   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
613       .AddPacket(30, 'c', kContFromPrevChunk)
614       .CopyIntoTraceBuffer();
615   CreateChunk(ProducerID(1), WriterID(2), ChunkID(0))
616       .AddPacket(10, 'd')
617       .CopyIntoTraceBuffer();
618   trace_buffer()->BeginRead();
619   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'd')));
620   ASSERT_THAT(ReadPacket(), IsEmpty());
621 
622   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
623       .AddPacket(20, 'b', kContFromPrevChunk | kContOnNextChunk)
624       .CopyIntoTraceBuffer();
625   CreateChunk(ProducerID(1), WriterID(1), ChunkID(3))
626       .AddPacket(40, 'd')
627       .CopyIntoTraceBuffer();
628   trace_buffer()->BeginRead();
629   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'a'),
630                                         FakePacketFragment(20, 'b'),
631                                         FakePacketFragment(30, 'c')));
632   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'd')));
633   ASSERT_THAT(ReadPacket(), IsEmpty());
634 }
635 
636 // Fragment order {-2,1,-1,0} for sequence {1,1}, without fragmenting packets.
TEST_F(TraceBufferTest,Fragments_OutOfOrderWithIdOverflowADCB)637 TEST_F(TraceBufferTest, Fragments_OutOfOrderWithIdOverflowADCB) {
638   ResetBuffer(4096);
639   CreateChunk(ProducerID(1), WriterID(1), ChunkID(kMaxChunkID - 1))
640       .AddPacket(10, 'a')
641       .CopyIntoTraceBuffer();
642   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
643       .AddPacket(40, 'd')
644       .CopyIntoTraceBuffer();
645   trace_buffer()->BeginRead();
646   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'a')));
647   ASSERT_THAT(ReadPacket(), IsEmpty());
648 
649   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
650       .AddPacket(30, 'c')
651       .CopyIntoTraceBuffer();
652   trace_buffer()->BeginRead();
653   ASSERT_THAT(ReadPacket(), IsEmpty());
654 
655   CreateChunk(ProducerID(1), WriterID(1), ChunkID(kMaxChunkID))
656       .AddPacket(20, 'b')
657       .CopyIntoTraceBuffer();
658   trace_buffer()->BeginRead();
659   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'b')));
660   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'c')));
661   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'd')));
662   ASSERT_THAT(ReadPacket(), IsEmpty());
663 }
664 
665 // Fragment order {-2,0,-1,1} for sequence {1,1}, without fragmenting packets.
TEST_F(TraceBufferTest,Fragments_OutOfOrderWithIdOverflowACBD)666 TEST_F(TraceBufferTest, Fragments_OutOfOrderWithIdOverflowACBD) {
667   ResetBuffer(4096);
668   CreateChunk(ProducerID(1), WriterID(1), ChunkID(kMaxChunkID - 1))
669       .AddPacket(10, 'a')
670       .CopyIntoTraceBuffer();
671   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
672       .AddPacket(30, 'c')
673       .CopyIntoTraceBuffer();
674   trace_buffer()->BeginRead();
675   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'a')));
676   ASSERT_THAT(ReadPacket(), IsEmpty());
677 
678   CreateChunk(ProducerID(1), WriterID(1), ChunkID(kMaxChunkID))
679       .AddPacket(20, 'b')
680       .CopyIntoTraceBuffer();
681   trace_buffer()->BeginRead();
682   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'b')));
683   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'c')));
684   ASSERT_THAT(ReadPacket(), IsEmpty());
685 
686   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
687       .AddPacket(40, 'd')
688       .CopyIntoTraceBuffer();
689   trace_buffer()->BeginRead();
690   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'd')));
691   ASSERT_THAT(ReadPacket(), IsEmpty());
692 }
693 
TEST_F(TraceBufferTest,Fragments_EmptyChunkBefore)694 TEST_F(TraceBufferTest, Fragments_EmptyChunkBefore) {
695   ResetBuffer(4096);
696   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0)).CopyIntoTraceBuffer();
697   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
698       .AddPacket(10, 'a')
699       .AddPacket(20, 'b', kContOnNextChunk)
700       .CopyIntoTraceBuffer();
701   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
702       .AddPacket(30, 'c', kContFromPrevChunk)
703       .AddPacket(40, 'd', kContOnNextChunk)
704       .CopyIntoTraceBuffer();
705   trace_buffer()->BeginRead();
706   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'a')));
707   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'b'),
708                                         FakePacketFragment(30, 'c')));
709   ASSERT_THAT(ReadPacket(), IsEmpty());
710 }
711 
TEST_F(TraceBufferTest,Fragments_EmptyChunkAfter)712 TEST_F(TraceBufferTest, Fragments_EmptyChunkAfter) {
713   ResetBuffer(4096);
714   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
715       .AddPacket(10, 'a')
716       .AddPacket(10, 'b', kContOnNextChunk)
717       .CopyIntoTraceBuffer();
718   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1)).CopyIntoTraceBuffer();
719   trace_buffer()->BeginRead();
720   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'a')));
721   ASSERT_THAT(ReadPacket(), IsEmpty());
722 }
723 
724 // Set up a fragmented packet that happens to also have an empty chunk in the
725 // middle of the sequence. Test that it just gets skipped.
TEST_F(TraceBufferTest,Fragments_EmptyChunkInTheMiddle)726 TEST_F(TraceBufferTest, Fragments_EmptyChunkInTheMiddle) {
727   ResetBuffer(4096);
728   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
729       .AddPacket(10, 'a', kContOnNextChunk)
730       .CopyIntoTraceBuffer();
731   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1)).CopyIntoTraceBuffer();
732   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
733       .AddPacket(10, 'b', kContFromPrevChunk)
734       .AddPacket(20, 'c')
735       .CopyIntoTraceBuffer();
736   trace_buffer()->BeginRead();
737   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'a'),
738                                         FakePacketFragment(10, 'b')));
739   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'c')));
740   ASSERT_THAT(ReadPacket(), IsEmpty());
741 }
742 
743 // Generates sequences of fragmented packets of increasing length (|seq_len|),
744 // from [P0, P1a][P1y] to [P0, P1a][P1b][P1c]...[P1y]. Test that they are always
745 // read as one packet.
TEST_F(TraceBufferTest,Fragments_LongPackets)746 TEST_F(TraceBufferTest, Fragments_LongPackets) {
747   for (unsigned seq_len = 1; seq_len <= 10; seq_len++) {
748     ResetBuffer(4096);
749     std::vector<FakePacketFragment> expected_fragments;
750     expected_fragments.emplace_back(20, 'b');
751     CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
752         .AddPacket(10, 'a')
753         .AddPacket(20, 'b', kContOnNextChunk)
754         .CopyIntoTraceBuffer();
755     for (unsigned i = 1; i <= seq_len; i++) {
756       char prefix = 'b' + static_cast<char>(i);
757       expected_fragments.emplace_back(20 + i, prefix);
758       CreateChunk(ProducerID(1), WriterID(1), ChunkID(i))
759           .AddPacket(20 + i, prefix, kContFromPrevChunk | kContOnNextChunk)
760           .CopyIntoTraceBuffer();
761     }
762     expected_fragments.emplace_back(30, 'y');
763     CreateChunk(ProducerID(1), WriterID(1), ChunkID(seq_len + 1))
764         .AddPacket(30, 'y', kContFromPrevChunk)
765         .AddPacket(50, 'z')
766         .CopyIntoTraceBuffer();
767 
768     trace_buffer()->BeginRead();
769     ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'a')));
770     ASSERT_THAT(ReadPacket(), ContainerEq(expected_fragments));
771     ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(50, 'z')));
772     ASSERT_THAT(ReadPacket(), IsEmpty());
773   }
774 }
775 
776 // Similar to Fragments_LongPacket, but covers also the case of ChunkID wrapping
777 // over its max value.
TEST_F(TraceBufferTest,Fragments_LongPacketWithWrappingID)778 TEST_F(TraceBufferTest, Fragments_LongPacketWithWrappingID) {
779   ResetBuffer(4096);
780   std::vector<FakePacketFragment> expected_fragments;
781 
782   for (ChunkID chunk_id = static_cast<ChunkID>(-2); chunk_id <= 2; chunk_id++) {
783     char prefix = static_cast<char>('c' + chunk_id);
784     expected_fragments.emplace_back(10 + chunk_id, prefix);
785     CreateChunk(ProducerID(1), WriterID(1), chunk_id)
786         .AddPacket(10 + chunk_id, prefix, kContOnNextChunk)
787         .CopyIntoTraceBuffer();
788   }
789   trace_buffer()->BeginRead();
790   ASSERT_THAT(ReadPacket(), ContainerEq(expected_fragments));
791   ASSERT_THAT(ReadPacket(), IsEmpty());
792 }
793 
TEST_F(TraceBufferTest,Fragments_PreserveUID)794 TEST_F(TraceBufferTest, Fragments_PreserveUID) {
795   ResetBuffer(4096);
796   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
797       .AddPacket(10, 'a')
798       .AddPacket(10, 'b', kContOnNextChunk)
799       .SetUID(11)
800       .CopyIntoTraceBuffer();
801   CreateChunk(ProducerID(2), WriterID(1), ChunkID(0))
802       .AddPacket(10, 'c')
803       .AddPacket(10, 'd')
804       .SetUID(22)
805       .CopyIntoTraceBuffer();
806   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
807       .AddPacket(10, 'e', kContFromPrevChunk)
808       .AddPacket(10, 'f')
809       .SetUID(11)
810       .CopyIntoTraceBuffer();
811   trace_buffer()->BeginRead();
812   TraceBuffer::PacketSequenceProperties sequence_properties;
813   ASSERT_THAT(ReadPacket(&sequence_properties),
814               ElementsAre(FakePacketFragment(10, 'a')));
815   ASSERT_EQ(static_cast<uid_t>(11), sequence_properties.producer_uid_trusted());
816 
817   ASSERT_THAT(
818       ReadPacket(&sequence_properties),
819       ElementsAre(FakePacketFragment(10, 'b'), FakePacketFragment(10, 'e')));
820   ASSERT_EQ(static_cast<uid_t>(11), sequence_properties.producer_uid_trusted());
821 
822   ASSERT_THAT(ReadPacket(&sequence_properties),
823               ElementsAre(FakePacketFragment(10, 'f')));
824   ASSERT_EQ(static_cast<uid_t>(11), sequence_properties.producer_uid_trusted());
825 
826   ASSERT_THAT(ReadPacket(&sequence_properties),
827               ElementsAre(FakePacketFragment(10, 'c')));
828   ASSERT_EQ(static_cast<uid_t>(22), sequence_properties.producer_uid_trusted());
829 
830   ASSERT_THAT(ReadPacket(&sequence_properties),
831               ElementsAre(FakePacketFragment(10, 'd')));
832   ASSERT_EQ(static_cast<uid_t>(22), sequence_properties.producer_uid_trusted());
833 
834   ASSERT_THAT(ReadPacket(), IsEmpty());
835 }
836 
TEST_F(TraceBufferTest,Fragments_DiscardedOnPacketSizeDropPacket)837 TEST_F(TraceBufferTest, Fragments_DiscardedOnPacketSizeDropPacket) {
838   ResetBuffer(4096);
839   // Set up a fragmented packet in the first chunk, which continues in the
840   // second chunk with kPacketSizeDropPacket size. The corrupted fragmented
841   // packet should be skipped.
842   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
843       .AddPacket(10, 'a')
844       .AddPacket(10, 'b', kContOnNextChunk)
845       .CopyIntoTraceBuffer();
846   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
847       .SetFlags(kContFromPrevChunk)
848       // Var-int encoded TraceWriterImpl::kPacketSizeDropPacket.
849       .AddPacket({0xff, 0xff, 0xff, 0x7f})
850       .CopyIntoTraceBuffer();
851   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
852       .AddPacket(10, 'd')
853       .CopyIntoTraceBuffer();
854   trace_buffer()->BeginRead();
855   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'a')));
856   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'd')));
857   ASSERT_THAT(ReadPacket(), IsEmpty());
858 }
859 
TEST_F(TraceBufferTest,Fragments_IncompleteChunkNeedsPatching)860 TEST_F(TraceBufferTest, Fragments_IncompleteChunkNeedsPatching) {
861   ResetBuffer(4096);
862   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
863       .AddPacket(20, 'a')
864       .AddPacket(30, 'b', kContOnNextChunk | kChunkNeedsPatching)
865       .PadTo(512)
866       .CopyIntoTraceBuffer(/*chunk_complete=*/false);
867   trace_buffer()->BeginRead();
868   // First packet should be read even if the chunk's last packet still needs
869   // patching.
870   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'a')));
871   ASSERT_THAT(ReadPacket(), IsEmpty());
872 }
873 
874 // --------------------------
875 // Out of band patching tests
876 // --------------------------
877 
TEST_F(TraceBufferTest,Patching_Simple)878 TEST_F(TraceBufferTest, Patching_Simple) {
879   ResetBuffer(4096);
880   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
881       .AddPacket(100, 'a')
882       .CopyIntoTraceBuffer();
883   CreateChunk(ProducerID(2), WriterID(1), ChunkID(0))
884       .AddPacket(9, 'b')
885       .ClearBytes(5, 4)  // 5 := 4th payload byte. Byte 0 is the varint header.
886       .CopyIntoTraceBuffer();
887   CreateChunk(ProducerID(3), WriterID(1), ChunkID(0))
888       .AddPacket(100, 'c')
889       .CopyIntoTraceBuffer();
890   ASSERT_TRUE(TryPatchChunkContents(ProducerID(2), WriterID(1), ChunkID(0),
891                                     {{5, {{'Y', 'M', 'C', 'A'}}}}));
892   trace_buffer()->BeginRead();
893   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(100, 'a')));
894   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment("b00-YMCA", 8)));
895   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(100, 'c')));
896   ASSERT_THAT(ReadPacket(), IsEmpty());
897 }
898 
TEST_F(TraceBufferTest,Patching_SkipIfChunkDoesntExist)899 TEST_F(TraceBufferTest, Patching_SkipIfChunkDoesntExist) {
900   ResetBuffer(4096);
901   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
902       .AddPacket(100, 'a')
903       .CopyIntoTraceBuffer();
904   ASSERT_FALSE(TryPatchChunkContents(ProducerID(1), WriterID(2), ChunkID(0),
905                                      {{0, {{'X', 'X', 'X', 'X'}}}}));
906   ASSERT_FALSE(TryPatchChunkContents(ProducerID(1), WriterID(1), ChunkID(1),
907                                      {{0, {{'X', 'X', 'X', 'X'}}}}));
908   ASSERT_FALSE(TryPatchChunkContents(ProducerID(1), WriterID(1), ChunkID(-1),
909                                      {{0, {{'X', 'X', 'X', 'X'}}}}));
910   trace_buffer()->BeginRead();
911   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(100, 'a')));
912   ASSERT_THAT(ReadPacket(), IsEmpty());
913 }
914 
TEST_F(TraceBufferTest,Patching_AtBoundariesOfChunk)915 TEST_F(TraceBufferTest, Patching_AtBoundariesOfChunk) {
916   ResetBuffer(4096);
917   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
918       .AddPacket(100, 'a', kContOnNextChunk)
919       .CopyIntoTraceBuffer();
920   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
921       .AddPacket(16, 'b', kContFromPrevChunk | kContOnNextChunk)
922       .ClearBytes(1, 4)
923       .ClearBytes(16 - 4, 4)
924       .CopyIntoTraceBuffer();
925   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
926       .AddPacket(100, 'c', kContFromPrevChunk)
927       .CopyIntoTraceBuffer();
928   ASSERT_TRUE(TryPatchChunkContents(
929       ProducerID(1), WriterID(1), ChunkID(1),
930       {{1, {{'P', 'E', 'R', 'F'}}}, {16 - 4, {{'E', 'T', 'T', 'O'}}}}));
931   trace_buffer()->BeginRead();
932   ASSERT_THAT(ReadPacket(),
933               ElementsAre(FakePacketFragment(100, 'a'),
934                           FakePacketFragment("PERFb01-b02ETTO", 15),
935                           FakePacketFragment(100, 'c')));
936   ASSERT_THAT(ReadPacket(), IsEmpty());
937 }
938 
939 // Tests kChunkNeedsPatching logic: chunks that are marked as "pending patch"
940 // should not be read until the patch has happened.
TEST_F(TraceBufferTest,Patching_ReadWaitsForPatchComplete)941 TEST_F(TraceBufferTest, Patching_ReadWaitsForPatchComplete) {
942   ResetBuffer(4096);
943 
944   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
945       .AddPacket(16, 'a', kChunkNeedsPatching)
946       .ClearBytes(1, 4)  // 1 := 0th payload byte. Byte 0 is the varint header.
947       .CopyIntoTraceBuffer();
948   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
949       .AddPacket(16, 'b')
950       .CopyIntoTraceBuffer();
951 
952   CreateChunk(ProducerID(2), WriterID(1), ChunkID(0))
953       .AddPacket(16, 'c')
954       .CopyIntoTraceBuffer();
955   CreateChunk(ProducerID(2), WriterID(1), ChunkID(1))
956       .AddPacket(16, 'd', kChunkNeedsPatching)
957       .ClearBytes(1, 4)  // 1 := 0th payload byte. Byte 0 is the varint header.
958       .CopyIntoTraceBuffer();
959   CreateChunk(ProducerID(2), WriterID(1), ChunkID(2))
960       .AddPacket(16, 'e')
961       .CopyIntoTraceBuffer();
962 
963   CreateChunk(ProducerID(3), WriterID(1), ChunkID(0))
964       .AddPacket(16, 'f', kChunkNeedsPatching)
965       .ClearBytes(1, 8)  // 1 := 0th payload byte. Byte 0 is the varint header.
966       .CopyIntoTraceBuffer();
967 
968   // The only thing that can be read right now is the 1st packet of the 2nd
969   // sequence. All the rest is blocked waiting for patching.
970   trace_buffer()->BeginRead();
971   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(16, 'c')));
972   ASSERT_THAT(ReadPacket(), IsEmpty());
973 
974   // Now patch the 2nd sequence and check that the sequence is unblocked.
975   ASSERT_TRUE(TryPatchChunkContents(ProducerID(2), WriterID(1), ChunkID(1),
976                                     {{1, {{'P', 'A', 'T', 'C'}}}}));
977   trace_buffer()->BeginRead();
978   ASSERT_THAT(ReadPacket(),
979               ElementsAre(FakePacketFragment("PATCd01-d02-d03", 15)));
980   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(16, 'e')));
981   ASSERT_THAT(ReadPacket(), IsEmpty());
982 
983   // Now patch the 3rd sequence, but in the first patch set
984   // |other_patches_pending| to true, so that the sequence is unblocked only
985   // after the 2nd patch.
986   ASSERT_TRUE(TryPatchChunkContents(ProducerID(3), WriterID(1), ChunkID(0),
987                                     {{1, {{'P', 'E', 'R', 'F'}}}},
988                                     /*other_patches_pending=*/true));
989   trace_buffer()->BeginRead();
990   ASSERT_THAT(ReadPacket(), IsEmpty());
991 
992   ASSERT_TRUE(TryPatchChunkContents(ProducerID(3), WriterID(1), ChunkID(0),
993                                     {{5, {{'E', 'T', 'T', 'O'}}}},
994                                     /*other_patches_pending=*/false));
995   trace_buffer()->BeginRead();
996   ASSERT_THAT(ReadPacket(),
997               ElementsAre(FakePacketFragment("PERFETTOf02-f03", 15)));
998   ASSERT_THAT(ReadPacket(), IsEmpty());
999 
1000 }  // namespace perfetto
1001 
1002 // ---------------------
1003 // Malicious input tests
1004 // ---------------------
1005 
TEST_F(TraceBufferTest,Malicious_ZeroSizedChunk)1006 TEST_F(TraceBufferTest, Malicious_ZeroSizedChunk) {
1007   ResetBuffer(4096);
1008   SuppressClientDchecksForTesting();
1009   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1010       .AddPacket(32, 'a')
1011       .CopyIntoTraceBuffer();
1012 
1013   uint8_t valid_ptr = 0;
1014   trace_buffer()->CopyChunkUntrusted(
1015       ProducerID(1), ClientIdentity(uid_t(0), pid_t(0)), WriterID(1),
1016       ChunkID(1), 1 /* num packets */, 0 /* flags */, true /* chunk_complete */,
1017       &valid_ptr, sizeof(valid_ptr));
1018 
1019   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
1020       .AddPacket(32, 'b')
1021       .CopyIntoTraceBuffer();
1022 
1023   trace_buffer()->BeginRead();
1024   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(32, 'a')));
1025   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(32, 'b')));
1026   ASSERT_THAT(ReadPacket(), IsEmpty());
1027 }
1028 
1029 // Attempting to write a chunk bigger than ChunkRecord::kMaxSize should end up
1030 // in a no-op.
TEST_F(TraceBufferTest,Malicious_ChunkTooBig)1031 TEST_F(TraceBufferTest, Malicious_ChunkTooBig) {
1032   ResetBuffer(4096);
1033   SuppressClientDchecksForTesting();
1034   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1035       .AddPacket(4096, 'a')
1036       .AddPacket(2048, 'b')
1037       .CopyIntoTraceBuffer();
1038   trace_buffer()->BeginRead();
1039   ASSERT_THAT(ReadPacket(), IsEmpty());
1040 }
1041 
TEST_F(TraceBufferTest,Malicious_DeclareMorePacketsBeyondBoundaries)1042 TEST_F(TraceBufferTest, Malicious_DeclareMorePacketsBeyondBoundaries) {
1043   ResetBuffer(4096);
1044   SuppressClientDchecksForTesting();
1045   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1046       .AddPacket(64, 'a')
1047       .IncrementNumPackets()
1048       .IncrementNumPackets()
1049       .CopyIntoTraceBuffer();
1050   CreateChunk(ProducerID(1), WriterID(2), ChunkID(0))
1051       .IncrementNumPackets()
1052       .CopyIntoTraceBuffer();
1053   CreateChunk(ProducerID(1), WriterID(3), ChunkID(0))
1054       .AddPacket(32, 'b')
1055       .CopyIntoTraceBuffer();
1056   trace_buffer()->BeginRead();
1057   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(64, 'a')));
1058   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(32, 'b')));
1059   ASSERT_THAT(ReadPacket(), IsEmpty());
1060   ASSERT_THAT(ReadPacket(), IsEmpty());
1061 }
1062 
TEST_F(TraceBufferTest,Malicious_ZeroVarintHeader)1063 TEST_F(TraceBufferTest, Malicious_ZeroVarintHeader) {
1064   ResetBuffer(4096);
1065   SuppressClientDchecksForTesting();
1066   // Create a standalone chunk where the varint header is == 0.
1067   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1068       .AddPacket(4, 'a')
1069       .ClearBytes(0, 1)
1070       .AddPacket(4, 'b')
1071       .CopyIntoTraceBuffer();
1072   CreateChunk(ProducerID(2), WriterID(1), ChunkID(0))
1073       .AddPacket(4, 'c')
1074       .CopyIntoTraceBuffer();
1075   trace_buffer()->BeginRead();
1076   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4, 'c')));
1077   ASSERT_THAT(ReadPacket(), IsEmpty());
1078 }
1079 
1080 // Forge a chunk where the first packet is valid but the second packet has a
1081 // varint header that continues beyond the end of the chunk (and also beyond the
1082 // end of the buffer).
TEST_F(TraceBufferTest,Malicious_OverflowingVarintHeader)1083 TEST_F(TraceBufferTest, Malicious_OverflowingVarintHeader) {
1084   ResetBuffer(4096);
1085   SuppressClientDchecksForTesting();
1086   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1087       .AddPacket(4079, 'a')  // 4079 := 4096 - sizeof(ChunkRecord) - 1
1088       .AddPacket({0x82})  // 0x8*: that the varint continues on the next byte.
1089       .CopyIntoTraceBuffer();
1090   trace_buffer()->BeginRead();
1091   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4079, 'a')));
1092   ASSERT_THAT(ReadPacket(), IsEmpty());
1093   ASSERT_THAT(ReadPacket(), IsEmpty());
1094 }
1095 
TEST_F(TraceBufferTest,Malicious_VarintHeaderTooBig)1096 TEST_F(TraceBufferTest, Malicious_VarintHeaderTooBig) {
1097   ResetBuffer(4096);
1098   SuppressClientDchecksForTesting();
1099 
1100   // Add a valid chunk.
1101   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1102       .AddPacket(32, 'a')
1103       .CopyIntoTraceBuffer();
1104 
1105   // Forge a packet which has a varint header that is just off by one.
1106   CreateChunk(ProducerID(2), WriterID(1), ChunkID(0))
1107       .AddPacket({0x16, '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b',
1108                   'c', 'd', 'e', 'f'})
1109       .CopyIntoTraceBuffer();
1110 
1111   // Forge a packet which has a varint header that tries to hit an overflow.
1112   CreateChunk(ProducerID(3), WriterID(1), ChunkID(0))
1113       .AddPacket({0xff, 0xff, 0xff, 0x7f})
1114       .CopyIntoTraceBuffer();
1115 
1116   // Forge a packet which has a jumbo varint header: 0xff, 0xff .. 0x7f.
1117   std::vector<uint8_t> chunk;
1118   chunk.insert(chunk.end(), 128 - sizeof(ChunkRecord), 0xff);
1119   chunk.back() = 0x7f;
1120   trace_buffer()->CopyChunkUntrusted(
1121       ProducerID(4), ClientIdentity(uid_t(0), pid_t(0)), WriterID(1),
1122       ChunkID(1), 1 /* num packets */, 0 /* flags*/, true /* chunk_complete */,
1123       chunk.data(), chunk.size());
1124 
1125   // Add a valid chunk.
1126   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
1127       .AddPacket(32, 'b')
1128       .CopyIntoTraceBuffer();
1129 
1130   trace_buffer()->BeginRead();
1131   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(32, 'a')));
1132   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(32, 'b')));
1133   ASSERT_THAT(ReadPacket(), IsEmpty());
1134 }
1135 
1136 // Similar to Malicious_VarintHeaderTooBig, but this time the full chunk
1137 // contains an enormous varint number that tries to overflow.
TEST_F(TraceBufferTest,Malicious_JumboVarint)1138 TEST_F(TraceBufferTest, Malicious_JumboVarint) {
1139   ResetBuffer(64 * 1024);
1140   SuppressClientDchecksForTesting();
1141 
1142   std::vector<uint8_t> chunk;
1143   chunk.insert(chunk.end(), 64 * 1024 - sizeof(ChunkRecord) * 2, 0xff);
1144   chunk.back() = 0x7f;
1145   for (int i = 0; i < 3; i++) {
1146     trace_buffer()->CopyChunkUntrusted(
1147         ProducerID(1), ClientIdentity(uid_t(0), pid_t(0)), WriterID(1),
1148         ChunkID(1), 1 /* num packets */, 0 /* flags */,
1149         true /* chunk_complete */, chunk.data(), chunk.size());
1150   }
1151 
1152   trace_buffer()->BeginRead();
1153   ASSERT_THAT(ReadPacket(), IsEmpty());
1154 }
1155 
1156 // Like the Malicious_ZeroVarintHeader, but put the chunk in the middle of a
1157 // sequence that would be otherwise valid. The zero-sized fragment should be
1158 // skipped.
TEST_F(TraceBufferTest,Malicious_ZeroVarintHeaderInSequence)1159 TEST_F(TraceBufferTest, Malicious_ZeroVarintHeaderInSequence) {
1160   ResetBuffer(4096);
1161   SuppressClientDchecksForTesting();
1162   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1163       .AddPacket(4, 'a', kContOnNextChunk)
1164       .CopyIntoTraceBuffer();
1165   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
1166       .AddPacket(4, 'b', kContFromPrevChunk | kContOnNextChunk)
1167       .ClearBytes(0, 1)
1168       .CopyIntoTraceBuffer();
1169   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
1170       .AddPacket(4, 'c', kContFromPrevChunk)
1171       .AddPacket(4, 'd')
1172       .CopyIntoTraceBuffer();
1173   CreateChunk(ProducerID(1), WriterID(1), ChunkID(3))
1174       .AddPacket(4, 'e')
1175       .CopyIntoTraceBuffer();
1176   CreateChunk(ProducerID(2), WriterID(1), ChunkID(3))
1177       .AddPacket(5, 'f')
1178       .CopyIntoTraceBuffer();
1179 
1180   trace_buffer()->BeginRead();
1181   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4, 'a'),
1182                                         FakePacketFragment(4, 'c')));
1183   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4, 'd')));
1184   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4, 'e')));
1185   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(5, 'f')));
1186   ASSERT_THAT(ReadPacket(), IsEmpty());
1187 }
1188 
1189 // Similar to Malicious_ZeroVarintHeaderInSequence, but this time the zero-sized
1190 // fragment is the last fragment for a chunk and is marked for continuation. The
1191 // zero-sized fragment should be skipped.
TEST_F(TraceBufferTest,Malicious_ZeroVarintHeaderAtEndOfChunk)1192 TEST_F(TraceBufferTest, Malicious_ZeroVarintHeaderAtEndOfChunk) {
1193   ResetBuffer(4096);
1194   SuppressClientDchecksForTesting();
1195   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1196       .AddPacket(4, 'a')
1197       .AddPacket(4, 'b', kContOnNextChunk)
1198       .ClearBytes(4, 4)
1199       .CopyIntoTraceBuffer();
1200   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
1201       .AddPacket(4, 'c', kContFromPrevChunk)
1202       .AddPacket(4, 'd')
1203       .CopyIntoTraceBuffer();
1204   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
1205       .AddPacket(4, 'e')
1206       .CopyIntoTraceBuffer();
1207   CreateChunk(ProducerID(2), WriterID(1), ChunkID(3))
1208       .AddPacket(4, 'f')
1209       .CopyIntoTraceBuffer();
1210 
1211   trace_buffer()->BeginRead();
1212   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4, 'a')));
1213   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4, 'c')));
1214   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4, 'd')));
1215   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4, 'e')));
1216   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4, 'f')));
1217   ASSERT_THAT(ReadPacket(), IsEmpty());
1218 }
1219 
TEST_F(TraceBufferTest,Malicious_PatchOutOfBounds)1220 TEST_F(TraceBufferTest, Malicious_PatchOutOfBounds) {
1221   ResetBuffer(4096);
1222   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1223       .AddPacket(2048, 'a')
1224       .CopyIntoTraceBuffer();
1225   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
1226       .AddPacket(16, 'b')
1227       .CopyIntoTraceBuffer();
1228   size_t offsets[] = {13,          16,          size_t(-4),
1229                       size_t(-8),  size_t(-12), size_t(-16),
1230                       size_t(-20), size_t(-32), size_t(-1024)};
1231   for (size_t offset : offsets) {
1232     ASSERT_FALSE(TryPatchChunkContents(ProducerID(1), WriterID(1), ChunkID(1),
1233                                        {{offset, {{'0', 'd', 'a', 'y'}}}}));
1234   }
1235 }
1236 
TEST_F(TraceBufferTest,Malicious_OverrideWithShorterChunkSize)1237 TEST_F(TraceBufferTest, Malicious_OverrideWithShorterChunkSize) {
1238   ResetBuffer(4096);
1239   SuppressClientDchecksForTesting();
1240   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1241       .AddPacket(2048, 'a')
1242       .CopyIntoTraceBuffer();
1243   // The service should ignore this override of the chunk since the chunk size
1244   // is different.
1245   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1246       .AddPacket(1024, 'b')
1247       .CopyIntoTraceBuffer();
1248   trace_buffer()->BeginRead();
1249   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(2048, 'a')));
1250   ASSERT_THAT(ReadPacket(), IsEmpty());
1251 }
1252 
TEST_F(TraceBufferTest,Malicious_OverrideWithShorterChunkSizeAfterRead)1253 TEST_F(TraceBufferTest, Malicious_OverrideWithShorterChunkSizeAfterRead) {
1254   ResetBuffer(4096);
1255   SuppressClientDchecksForTesting();
1256 
1257   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1258       .AddPacket(30, 'a')
1259       .AddPacket(40, 'b')
1260       .CopyIntoTraceBuffer();
1261   trace_buffer()->BeginRead();
1262   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'a')));
1263   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'b')));
1264 
1265   // The service should ignore this override of the chunk since the chunk size
1266   // is different.
1267   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1268       .AddPacket(10, 'a')
1269       .AddPacket(10, 'b')
1270       .AddPacket(10, 'c')
1271       .CopyIntoTraceBuffer();
1272   trace_buffer()->BeginRead();
1273   ASSERT_THAT(ReadPacket(), IsEmpty());
1274 
1275   // Test that the service didn't get stuck in some indeterminate state.
1276   // Writing a valid chunk with a larger ID should make things work again.
1277   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
1278       .AddPacket(10, 'd')
1279       .AddPacket(10, 'e')
1280       .CopyIntoTraceBuffer();
1281   trace_buffer()->BeginRead();
1282   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'd')));
1283   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'e')));
1284   ASSERT_THAT(ReadPacket(), IsEmpty());
1285 }
1286 
TEST_F(TraceBufferTest,Malicious_OverrideWithDifferentOffsetAfterRead)1287 TEST_F(TraceBufferTest, Malicious_OverrideWithDifferentOffsetAfterRead) {
1288   ResetBuffer(4096);
1289   SuppressClientDchecksForTesting();
1290 
1291   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1292       .AddPacket(30, 'a')
1293       .AddPacket(40, 'b')
1294       .PadTo(512)
1295       .CopyIntoTraceBuffer();
1296   trace_buffer()->BeginRead();
1297   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'a')));
1298   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'b')));
1299 
1300   // The attacker in this case speculates on the fact that the read pointer is
1301   // @ 70 which is >> the size of the new chunk we overwrite.
1302   // The service will not discard this override since the chunk size is correct.
1303   // However, it should detect that the packet headers at the current read
1304   // offset are invalid and skip the read of this chunk.
1305   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1306       .AddPacket(10, 'a')
1307       .AddPacket(10, 'b')
1308       .AddPacket(10, 'c')
1309       .PadTo(512)
1310       .CopyIntoTraceBuffer();
1311   trace_buffer()->BeginRead();
1312   ASSERT_THAT(ReadPacket(), IsEmpty());
1313 
1314   // Test that the service didn't get stuck in some indeterminate state.
1315   // Writing a valid chunk with a larger ID should make things work again.
1316   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
1317       .AddPacket(10, 'd')
1318       .AddPacket(10, 'e')
1319       .PadTo(512)
1320       .CopyIntoTraceBuffer();
1321   trace_buffer()->BeginRead();
1322   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'd')));
1323   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(10, 'e')));
1324   ASSERT_THAT(ReadPacket(), IsEmpty());
1325 }
1326 
1327 // -------------------
1328 // SequenceIterator tests
1329 // -------------------
TEST_F(TraceBufferTest,Iterator_OneStreamOrdered)1330 TEST_F(TraceBufferTest, Iterator_OneStreamOrdered) {
1331   ResetBuffer(64 * 1024);
1332   AppendChunks({
1333       {ProducerID(1), WriterID(1), ChunkID(0)},
1334       {ProducerID(1), WriterID(1), ChunkID(1)},
1335       {ProducerID(1), WriterID(1), ChunkID(2)},
1336       {ProducerID(1), WriterID(1), ChunkID(5)},
1337       {ProducerID(1), WriterID(1), ChunkID(6)},
1338       {ProducerID(1), WriterID(1), ChunkID(7)},
1339   });
1340   ASSERT_TRUE(IteratorSeqEq(ProducerID(1), WriterID(2), {}));
1341   ASSERT_TRUE(IteratorSeqEq(ProducerID(-1), WriterID(-1), {}));
1342   ASSERT_TRUE(IteratorSeqEq(ProducerID(1), WriterID(1), {0, 1, 2}));
1343 }
1344 
TEST_F(TraceBufferTest,Iterator_OneStreamWrapping)1345 TEST_F(TraceBufferTest, Iterator_OneStreamWrapping) {
1346   ResetBuffer(64 * 1024);
1347   AppendChunks({
1348       {ProducerID(1), WriterID(1), ChunkID(kMaxChunkID - 2)},
1349       {ProducerID(1), WriterID(1), ChunkID(kMaxChunkID - 1)},
1350       {ProducerID(1), WriterID(1), ChunkID(kMaxChunkID)},
1351       {ProducerID(1), WriterID(1), ChunkID(0)},
1352       {ProducerID(1), WriterID(1), ChunkID(1)},
1353       {ProducerID(1), WriterID(1), ChunkID(2)},
1354   });
1355   ASSERT_TRUE(IteratorSeqEq(ProducerID(1), WriterID(2), {}));
1356   ASSERT_TRUE(IteratorSeqEq(ProducerID(-1), WriterID(-1), {}));
1357   ASSERT_TRUE(
1358       IteratorSeqEq(ProducerID(1), WriterID(1),
1359                     {kMaxChunkID - 2, kMaxChunkID - 1, kMaxChunkID, 0, 1, 2}));
1360 }
1361 
TEST_F(TraceBufferTest,Iterator_ManyStreamsOrdered)1362 TEST_F(TraceBufferTest, Iterator_ManyStreamsOrdered) {
1363   ResetBuffer(64 * 1024);
1364   AppendChunks({
1365       {ProducerID(1), WriterID(1), ChunkID(0)},
1366       {ProducerID(1), WriterID(1), ChunkID(1)},
1367       {ProducerID(1), WriterID(2), ChunkID(0)},
1368       {ProducerID(3), WriterID(1), ChunkID(0)},
1369       {ProducerID(1), WriterID(2), ChunkID(1)},
1370       {ProducerID(1), WriterID(2), ChunkID(2)},
1371       {ProducerID(3), WriterID(1), ChunkID(1)},
1372       {ProducerID(1), WriterID(1), ChunkID(2)},
1373       {ProducerID(3), WriterID(1), ChunkID(2)},
1374   });
1375   ASSERT_TRUE(IteratorSeqEq(ProducerID(1), WriterID(1), {0, 1, 2}));
1376   ASSERT_TRUE(IteratorSeqEq(ProducerID(1), WriterID(2), {0, 1, 2}));
1377   ASSERT_TRUE(IteratorSeqEq(ProducerID(3), WriterID(1), {0, 1, 2}));
1378 }
1379 
TEST_F(TraceBufferTest,Iterator_ManyStreamsWrapping)1380 TEST_F(TraceBufferTest, Iterator_ManyStreamsWrapping) {
1381   ResetBuffer(64 * 1024);
1382   auto Neg = [](int x) -> ChunkID {
1383     return kMaxChunkID + static_cast<ChunkID>(x) + 1;
1384   };
1385   AppendChunks({
1386       {ProducerID(1), WriterID(1), ChunkID(Neg(-2))},
1387       {ProducerID(1), WriterID(1), ChunkID(Neg(-1))},
1388       {ProducerID(1), WriterID(2), ChunkID(Neg(-1))},
1389       {ProducerID(3), WriterID(1), ChunkID(Neg(-1))},
1390       {ProducerID(1), WriterID(2), ChunkID(0)},
1391       {ProducerID(1), WriterID(2), ChunkID(1)},
1392       {ProducerID(3), WriterID(1), ChunkID(0)},
1393       {ProducerID(1), WriterID(1), ChunkID(0)},
1394       {ProducerID(3), WriterID(1), ChunkID(1)},
1395   });
1396   ASSERT_TRUE(IteratorSeqEq(ProducerID(1), WriterID(1), {Neg(-2), Neg(-1), 0}));
1397   ASSERT_TRUE(IteratorSeqEq(ProducerID(1), WriterID(2), {Neg(-1), 0, 1}));
1398   ASSERT_TRUE(IteratorSeqEq(ProducerID(3), WriterID(1), {Neg(-1), 0, 1}));
1399 }
1400 
1401 // -------------------
1402 // Re-writing same chunk id
1403 // -------------------
1404 
TEST_F(TraceBufferTest,Override_ReCommitBeforeRead)1405 TEST_F(TraceBufferTest, Override_ReCommitBeforeRead) {
1406   ResetBuffer(4096);
1407   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1408       .AddPacket(100, 'a')
1409       .AddPacket(100, 'b')
1410       .PadTo(512)
1411       .CopyIntoTraceBuffer(/*chunk_complete=*/false);
1412   EXPECT_EQ(0u, trace_buffer()->stats().chunks_rewritten());
1413   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1414       .AddPacket(100, 'a')
1415       .AddPacket(100, 'b')
1416       .AddPacket(100, 'c')
1417       .AddPacket(100, 'd')
1418       .PadTo(512)
1419       .CopyIntoTraceBuffer();
1420   trace_buffer()->BeginRead();
1421   EXPECT_EQ(1u, trace_buffer()->stats().chunks_rewritten());
1422   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(100, 'a')));
1423   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(100, 'b')));
1424   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(100, 'c')));
1425   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(100, 'd')));
1426   ASSERT_THAT(ReadPacket(), IsEmpty());
1427 }
1428 
TEST_F(TraceBufferTest,Override_ReCommitAfterPartialRead)1429 TEST_F(TraceBufferTest, Override_ReCommitAfterPartialRead) {
1430   ResetBuffer(4096);
1431   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1432       .AddPacket(20, 'a')
1433       .AddPacket(30, 'b')
1434       .PadTo(512)
1435       .CopyIntoTraceBuffer(/*chunk_complete=*/false);
1436   trace_buffer()->BeginRead();
1437   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'a')));
1438 
1439   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1440       .AddPacket(20, 'a')
1441       .AddPacket(30, 'b')
1442       .AddPacket(40, 'c')
1443       .AddPacket(50, 'd')
1444       .PadTo(512)
1445       .CopyIntoTraceBuffer();
1446   trace_buffer()->BeginRead();
1447   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'b')));
1448   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'c')));
1449   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(50, 'd')));
1450   ASSERT_THAT(ReadPacket(), IsEmpty());
1451 }
1452 
TEST_F(TraceBufferTest,Override_ReCommitAfterFullRead)1453 TEST_F(TraceBufferTest, Override_ReCommitAfterFullRead) {
1454   ResetBuffer(4096);
1455   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1456       .AddPacket(20, 'a')
1457       .AddPacket(30, 'b')
1458       .PadTo(512)
1459       .CopyIntoTraceBuffer();
1460   trace_buffer()->BeginRead();
1461   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'a')));
1462   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'b')));
1463 
1464   // Overriding a complete packet here would trigger a DCHECK because the packet
1465   // was already marked as complete.
1466   SuppressClientDchecksForTesting();
1467   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1468       .AddPacket(20, 'a')
1469       .AddPacket(30, 'b')
1470       .AddPacket(40, 'c')
1471       .AddPacket(50, 'd')
1472       .PadTo(512)
1473       .CopyIntoTraceBuffer();
1474   trace_buffer()->BeginRead();
1475   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'c')));
1476   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(50, 'd')));
1477   ASSERT_THAT(ReadPacket(), IsEmpty());
1478 }
1479 
1480 // See also the Malicious_Override* tests above.
TEST_F(TraceBufferTest,Override_ReCommitInvalid)1481 TEST_F(TraceBufferTest, Override_ReCommitInvalid) {
1482   ResetBuffer(4096);
1483   SuppressClientDchecksForTesting();
1484   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1485       .AddPacket(20, 'a')
1486       .AddPacket(30, 'b')
1487       .PadTo(512)
1488       .CopyIntoTraceBuffer();
1489   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
1490       .AddPacket(40, 'c')
1491       .AddPacket(50, 'd')
1492       .PadTo(512)
1493       .CopyIntoTraceBuffer();
1494   trace_buffer()->BeginRead();
1495   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'a')));
1496   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'b')));
1497   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'c')));
1498 
1499   // This should not happen when the producer behaves correctly, since it
1500   // shouldn't change the contents of chunk 0 after having allocated chunk 1.
1501   //
1502   // Since we've already started reading from chunk 1, TraceBuffer will
1503   // recognize this and discard the override.
1504   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1505       .AddPacket(20, 'e')
1506       .AddPacket(60, 'f')
1507       .AddPacket(70, 'g')
1508       .PadTo(512)
1509       .CopyIntoTraceBuffer();
1510   trace_buffer()->BeginRead();
1511   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(50, 'd')));
1512   ASSERT_THAT(ReadPacket(), IsEmpty());
1513 }
1514 
TEST_F(TraceBufferTest,Override_ReCommitReordered)1515 TEST_F(TraceBufferTest, Override_ReCommitReordered) {
1516   ResetBuffer(4096);
1517   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1518       .AddPacket(20, 'a')
1519       .AddPacket(30, 'b')
1520       .PadTo(512)
1521       .CopyIntoTraceBuffer(/*chunk_complete=*/false);
1522 
1523   trace_buffer()->BeginRead();
1524   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'a')));
1525 
1526   // Recommit chunk 0 and add chunk 1, but do this out of order.
1527   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
1528       .AddPacket(50, 'd')
1529       .AddPacket(60, 'e')
1530       .PadTo(512)
1531       .CopyIntoTraceBuffer();
1532   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1533       .AddPacket(20, 'a')
1534       .AddPacket(30, 'b')
1535       .AddPacket(40, 'c')
1536       .PadTo(512)
1537       .CopyIntoTraceBuffer();
1538 
1539   trace_buffer()->BeginRead();
1540   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'b')));
1541   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'c')));
1542   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(50, 'd')));
1543   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(60, 'e')));
1544 }
1545 
TEST_F(TraceBufferTest,Override_ReCommitReorderedFragmenting)1546 TEST_F(TraceBufferTest, Override_ReCommitReorderedFragmenting) {
1547   ResetBuffer(4096);
1548   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1549       .AddPacket(20, 'a')
1550       .AddPacket(30, 'b')
1551       .PadTo(512)
1552       .CopyIntoTraceBuffer(/*chunk_complete=*/false);
1553 
1554   trace_buffer()->BeginRead();
1555   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'a')));
1556 
1557   // Recommit chunk 0 and add chunk 1, but do this out of order.
1558   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
1559       .AddPacket(50, 'd', kContFromPrevChunk)
1560       .AddPacket(60, 'e')
1561       .PadTo(512)
1562       .CopyIntoTraceBuffer();
1563   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1564       .AddPacket(20, 'a')
1565       .AddPacket(30, 'b')
1566       .AddPacket(40, 'c', kContOnNextChunk)
1567       .PadTo(512)
1568       .CopyIntoTraceBuffer();
1569 
1570   trace_buffer()->BeginRead();
1571   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'b')));
1572   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'c'),
1573                                         FakePacketFragment(50, 'd')));
1574   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(60, 'e')));
1575 }
1576 
TEST_F(TraceBufferTest,Override_ReCommitSameBeforeRead)1577 TEST_F(TraceBufferTest, Override_ReCommitSameBeforeRead) {
1578   ResetBuffer(4096);
1579   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1580       .AddPacket(20, 'a')
1581       .AddPacket(30, 'b')
1582       .PadTo(512)
1583       .CopyIntoTraceBuffer();
1584 
1585   // Commit again the same chunk.
1586   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1587       .AddPacket(20, 'a')
1588       .AddPacket(30, 'b')
1589       .PadTo(512)
1590       .CopyIntoTraceBuffer();
1591 
1592   // Then write some new content in a new chunk.
1593   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
1594       .AddPacket(40, 'c')
1595       .AddPacket(50, 'd')
1596       .PadTo(512)
1597       .CopyIntoTraceBuffer();
1598 
1599   // The reader should keep reading from the new chunk.
1600   trace_buffer()->BeginRead();
1601   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'a')));
1602   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'b')));
1603   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'c')));
1604   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(50, 'd')));
1605   ASSERT_THAT(ReadPacket(), IsEmpty());
1606 }
1607 
TEST_F(TraceBufferTest,Override_ReCommitSameAfterRead)1608 TEST_F(TraceBufferTest, Override_ReCommitSameAfterRead) {
1609   ResetBuffer(4096);
1610   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1611       .AddPacket(20, 'a')
1612       .AddPacket(30, 'b')
1613       .PadTo(512)
1614       .CopyIntoTraceBuffer();
1615   trace_buffer()->BeginRead();
1616   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'a')));
1617   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'b')));
1618 
1619   // This re-commit should be ignored. We just re-committed an identical chunk.
1620   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1621       .AddPacket(20, 'a')
1622       .AddPacket(30, 'b')
1623       .PadTo(512)
1624       .CopyIntoTraceBuffer();
1625 
1626   // Then write some new content in a new chunk.
1627   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
1628       .AddPacket(40, 'c')
1629       .AddPacket(50, 'd')
1630       .PadTo(512)
1631       .CopyIntoTraceBuffer();
1632 
1633   // The reader should keep reading from the new chunk.
1634   trace_buffer()->BeginRead();
1635   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'c')));
1636   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(50, 'd')));
1637   ASSERT_THAT(ReadPacket(), IsEmpty());
1638 }
1639 
TEST_F(TraceBufferTest,Override_ReCommitIncompleteAfterReadOutOfOrder)1640 TEST_F(TraceBufferTest, Override_ReCommitIncompleteAfterReadOutOfOrder) {
1641   ResetBuffer(4096);
1642   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1643       .AddPacket(20, 'a')
1644       .AddPacket(30, 'b')
1645       .PadTo(512)
1646       .CopyIntoTraceBuffer(/*chunk_complete=*/false);
1647   trace_buffer()->BeginRead();
1648   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'a')));
1649   // The last packet in an incomplete chunk should be ignored as the producer
1650   // may not have completed writing it.
1651   ASSERT_THAT(ReadPacket(), IsEmpty());
1652 
1653   // Then write some new content in a new chunk.
1654   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
1655       .AddPacket(40, 'c')
1656       .AddPacket(50, 'd')
1657       .PadTo(512)
1658       .CopyIntoTraceBuffer();
1659   // The read still shouldn't be advancing past the incomplete chunk.
1660   trace_buffer()->BeginRead();
1661   ASSERT_THAT(ReadPacket(), IsEmpty());
1662 
1663   // Recommit the original chunk with no changes but mark as complete.
1664   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1665       .AddPacket(20, 'a')
1666       .AddPacket(30, 'b')
1667       .PadTo(512)
1668       .CopyIntoTraceBuffer(/*chunk_complete=*/true);
1669 
1670   // Reading should resume from the now completed chunk.
1671   trace_buffer()->BeginRead();
1672   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'b')));
1673   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(40, 'c')));
1674   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(50, 'd')));
1675   ASSERT_THAT(ReadPacket(), IsEmpty());
1676 }
1677 
TEST_F(TraceBufferTest,Override_ReCommitIncompleteFragmenting)1678 TEST_F(TraceBufferTest, Override_ReCommitIncompleteFragmenting) {
1679   ResetBuffer(4096);
1680   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1681       .AddPacket(20, 'a')
1682       .AddPacket(30, 'b', kContOnNextChunk)
1683       .PadTo(512)
1684       .CopyIntoTraceBuffer(/*chunk_complete=*/false);
1685   trace_buffer()->BeginRead();
1686   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'a')));
1687   // The last packet in an incomplete chunk should be ignored as the producer
1688   // may not have completed writing it.
1689   ASSERT_THAT(ReadPacket(), IsEmpty());
1690 
1691   // Then write some new content in a new chunk.
1692   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
1693       .AddPacket(40, 'c', kContFromPrevChunk)
1694       .AddPacket(50, 'd')
1695       .PadTo(512)
1696       .CopyIntoTraceBuffer();
1697   // The read still shouldn't be advancing past the incomplete chunk.
1698   trace_buffer()->BeginRead();
1699   ASSERT_THAT(ReadPacket(), IsEmpty());
1700 
1701   // Recommit the original chunk with no changes but mark as complete.
1702   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1703       .AddPacket(20, 'a')
1704       .AddPacket(30, 'b', kContOnNextChunk)
1705       .PadTo(512)
1706       .CopyIntoTraceBuffer(/*chunk_complete=*/true);
1707 
1708   // Reading should resume from the now completed chunk.
1709   trace_buffer()->BeginRead();
1710   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'b'),
1711                                         FakePacketFragment(40, 'c')));
1712   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(50, 'd')));
1713   ASSERT_THAT(ReadPacket(), IsEmpty());
1714 }
1715 
TEST_F(TraceBufferTest,Override_EndOfBuffer)1716 TEST_F(TraceBufferTest, Override_EndOfBuffer) {
1717   ResetBuffer(3072);
1718   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1719       .AddPacket(20, 'a')
1720       .AddPacket(30, 'b')
1721       .PadTo(2048)
1722       .CopyIntoTraceBuffer(/*chunk_complete=*/false);
1723   trace_buffer()->BeginRead();
1724   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(20, 'a')));
1725   // The last packet in an incomplete chunk should be ignored as the producer
1726   // may not have completed writing it.
1727   ASSERT_THAT(ReadPacket(), IsEmpty());
1728 
1729   // Recommit the original chunk with no changes but mark as complete.
1730   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1731       .AddPacket(20, 'a')
1732       .AddPacket(30, 'b')
1733       .PadTo(2048)
1734       .CopyIntoTraceBuffer(/*chunk_complete=*/true);
1735 
1736   // Reading should resume from the now completed chunk.
1737   trace_buffer()->BeginRead();
1738   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(30, 'b')));
1739   ASSERT_THAT(ReadPacket(), IsEmpty());
1740 }
1741 
TEST_F(TraceBufferTest,DiscardPolicy)1742 TEST_F(TraceBufferTest, DiscardPolicy) {
1743   ResetBuffer(4096, TraceBuffer::kDiscard);
1744 
1745   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1746       .AddPacket(96 - 16, 'a')
1747       .CopyIntoTraceBuffer();
1748   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
1749       .AddPacket(4000 - 16, 'b')
1750       .CopyIntoTraceBuffer();
1751 
1752   trace_buffer()->BeginRead();
1753   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(96 - 16, 'a')));
1754 
1755   // As long as the reader catches up, writes should succeed.
1756   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
1757       .AddPacket(48 - 16, 'c')
1758       .CopyIntoTraceBuffer();
1759   CreateChunk(ProducerID(1), WriterID(1), ChunkID(3))
1760       .AddPacket(48 - 16, 'd')
1761       .CopyIntoTraceBuffer();
1762 
1763   trace_buffer()->BeginRead();
1764   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4000 - 16, 'b')));
1765   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(48 - 16, 'c')));
1766   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(48 - 16, 'd')));
1767   ASSERT_THAT(ReadPacket(), IsEmpty());
1768 
1769   // This will succeed.
1770   CreateChunk(ProducerID(1), WriterID(1), ChunkID(4))
1771       .AddPacket(4000 - 16, 'e')
1772       .CopyIntoTraceBuffer();
1773 
1774   // But this will fail, preventing any further write.
1775   for (int i = 0; i < 3; i++) {
1776     CreateChunk(ProducerID(1), WriterID(i + 2), ChunkID(0))
1777         .AddPacket(120 - 16, 'X')
1778         .CopyIntoTraceBuffer();
1779   }
1780 
1781   trace_buffer()->BeginRead();
1782   ASSERT_THAT(ReadPacket(), ElementsAre(FakePacketFragment(4000 - 16, 'e')));
1783   ASSERT_THAT(ReadPacket(), IsEmpty());
1784 
1785   // Even after the reader catches up, writes should still be discarded.
1786   for (int i = 0; i < 3; i++) {
1787     CreateChunk(ProducerID(1), WriterID(i + 10), ChunkID(0))
1788         .AddPacket(64 - 16, 'X')
1789         .CopyIntoTraceBuffer();
1790   }
1791   trace_buffer()->BeginRead();
1792   ASSERT_THAT(ReadPacket(), IsEmpty());
1793 }
1794 
TEST_F(TraceBufferTest,MissingPacketsOnSequence)1795 TEST_F(TraceBufferTest, MissingPacketsOnSequence) {
1796   ResetBuffer(4096);
1797   SuppressClientDchecksForTesting();
1798   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1799       .AddPacket(10, 'a')
1800       .AddPacket(10, 'b')
1801       .AddPacket(10, 'c', kContOnNextChunk)
1802       .CopyIntoTraceBuffer();
1803   CreateChunk(ProducerID(2), WriterID(1), ChunkID(0))
1804       .AddPacket(10, 'u')
1805       .AddPacket(10, 'v')
1806       .AddPacket(10, 'w')
1807       .ClearBytes(10, 1)  // Clears the varint header of packet "v".
1808       .CopyIntoTraceBuffer();
1809 
1810   bool previous_packet_dropped = false;
1811 
1812   trace_buffer()->BeginRead();
1813   ASSERT_THAT(ReadPacket(nullptr, &previous_packet_dropped),
1814               ElementsAre(FakePacketFragment(10, 'a')));
1815   // First packet in first sequence, so previous one didn't exist.
1816   ASSERT_TRUE(previous_packet_dropped);
1817 
1818   ASSERT_THAT(ReadPacket(nullptr, &previous_packet_dropped),
1819               ElementsAre(FakePacketFragment(10, 'b')));
1820   // We read packet "a" before.
1821   ASSERT_FALSE(previous_packet_dropped);
1822 
1823   ASSERT_THAT(ReadPacket(nullptr, &previous_packet_dropped),
1824               ElementsAre(FakePacketFragment(10, 'u')));
1825   // First packet in second sequence, so previous one didn't exist.
1826   ASSERT_TRUE(previous_packet_dropped);
1827 
1828   // Packet "v" in second sequence is corrupted, so chunk will be skipped.
1829   ASSERT_THAT(ReadPacket(), IsEmpty());
1830 
1831   CreateChunk(ProducerID(2), WriterID(1), ChunkID(1))
1832       .AddPacket(10, 'x')
1833       .AddPacket(10, 'y')
1834       .CopyIntoTraceBuffer();
1835   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
1836       .AddPacket(10, 'd', kContFromPrevChunk)
1837       .AddPacket(10, 'e')
1838       .CopyIntoTraceBuffer();
1839 
1840   trace_buffer()->BeginRead();
1841   ASSERT_THAT(
1842       ReadPacket(nullptr, &previous_packet_dropped),
1843       ElementsAre(FakePacketFragment(10, 'c'), FakePacketFragment(10, 'd')));
1844   // We read packet "b" before.
1845   ASSERT_FALSE(previous_packet_dropped);
1846 
1847   ASSERT_THAT(ReadPacket(nullptr, &previous_packet_dropped),
1848               ElementsAre(FakePacketFragment(10, 'e')));
1849   // We read packet "d" before.
1850   ASSERT_FALSE(previous_packet_dropped);
1851 
1852   ASSERT_THAT(ReadPacket(nullptr, &previous_packet_dropped),
1853               ElementsAre(FakePacketFragment(10, 'x')));
1854   // We didn't read packets "v" and "w".
1855   ASSERT_TRUE(previous_packet_dropped);
1856 
1857   ASSERT_THAT(ReadPacket(nullptr, &previous_packet_dropped),
1858               ElementsAre(FakePacketFragment(10, 'y')));
1859   // We read packet "x".
1860   ASSERT_FALSE(previous_packet_dropped);
1861 
1862   ASSERT_THAT(ReadPacket(), IsEmpty());
1863 
1864   // Write two large chunks that don't fit into the buffer at the same time. We
1865   // will drop the former one before we can read it.
1866   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
1867       .AddPacket(2000, 'f')
1868       .CopyIntoTraceBuffer();
1869   CreateChunk(ProducerID(1), WriterID(1), ChunkID(3))
1870       .AddPacket(3000, 'g')
1871       .CopyIntoTraceBuffer();
1872 
1873   trace_buffer()->BeginRead();
1874   ASSERT_THAT(ReadPacket(nullptr, &previous_packet_dropped),
1875               ElementsAre(FakePacketFragment(3000, 'g')));
1876   // We didn't read packet "f".
1877   ASSERT_TRUE(previous_packet_dropped);
1878 
1879   CreateChunk(ProducerID(2), WriterID(1), ChunkID(2))
1880       .AddPacket(10, 'z')
1881       .CopyIntoTraceBuffer();
1882 
1883   trace_buffer()->BeginRead();
1884   ASSERT_THAT(ReadPacket(nullptr, &previous_packet_dropped),
1885               ElementsAre(FakePacketFragment(10, 'z')));
1886   // We've lost any state from the second producer's sequence because all its
1887   // previous chunks were removed from the buffer due to the two large chunks.
1888   // So the buffer can't be sure that no packets were dropped.
1889   ASSERT_TRUE(previous_packet_dropped);
1890 }
1891 
TEST_F(TraceBufferTest,Clone_NoFragments)1892 TEST_F(TraceBufferTest, Clone_NoFragments) {
1893   const char kNumWriters = 3;
1894   for (char num_pre_reads = 0; num_pre_reads < kNumWriters; num_pre_reads++) {
1895     ResetBuffer(4096);
1896     for (char i = 'A'; i < 'A' + kNumWriters; i++) {
1897       ASSERT_EQ(32u, CreateChunk(ProducerID(i), WriterID(i), ChunkID(i))
1898                          .AddPacket(32 - 16, i)
1899                          .CopyIntoTraceBuffer());
1900     }
1901 
1902     ASSERT_EQ(trace_buffer()->used_size(), 32u * kNumWriters);
1903 
1904     // Make some reads *before* cloning. This is to check that the behaviour of
1905     // CloneReadOnly() is not affected by reads made before cloning.
1906     // On every round (|num_pre_reads|), read a different number of packets.
1907     for (char i = 0; i < num_pre_reads; i++) {
1908       if (i == 0)
1909         trace_buffer()->BeginRead();
1910       ASSERT_THAT(ReadPacket(),
1911                   ElementsAre(FakePacketFragment(32 - 16, 'A' + i)));
1912     }
1913 
1914     // Now create a snapshot and make sure we always read all the packets.
1915     std::unique_ptr<TraceBuffer> snap = trace_buffer()->CloneReadOnly();
1916     ASSERT_EQ(snap->used_size(), 32u * kNumWriters);
1917     snap->BeginRead();
1918     for (char i = 'A'; i < 'A' + kNumWriters; i++) {
1919       auto frags = ReadPacket(snap);
1920       ASSERT_THAT(frags, ElementsAre(FakePacketFragment(32 - 16, i)));
1921     }
1922     ASSERT_THAT(ReadPacket(snap), IsEmpty());
1923   }
1924 }
1925 
TEST_F(TraceBufferTest,Clone_FragmentsOutOfOrder)1926 TEST_F(TraceBufferTest, Clone_FragmentsOutOfOrder) {
1927   ResetBuffer(4096);
1928   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1929       .AddPacket(10, 'a')
1930       .CopyIntoTraceBuffer();
1931   CreateChunk(ProducerID(1), WriterID(1), ChunkID(2))
1932       .AddPacket(30, 'c')
1933       .CopyIntoTraceBuffer();
1934 
1935   {
1936     // Create a snapshot before the middle 'b' chunk is copied. Only 'a' should
1937     // be readable at this point.
1938     std::unique_ptr<TraceBuffer> snap = trace_buffer()->CloneReadOnly();
1939     snap->BeginRead();
1940     ASSERT_THAT(ReadPacket(snap), ElementsAre(FakePacketFragment(10, 'a')));
1941     ASSERT_THAT(ReadPacket(snap), IsEmpty());
1942   }
1943 
1944   CreateChunk(ProducerID(1), WriterID(1), ChunkID(1))
1945       .AddPacket(20, 'b')
1946       .CopyIntoTraceBuffer();
1947 
1948   // Now all three packes should be readable.
1949   std::unique_ptr<TraceBuffer> snap = trace_buffer()->CloneReadOnly();
1950   snap->BeginRead();
1951   ASSERT_THAT(ReadPacket(snap), ElementsAre(FakePacketFragment(10, 'a')));
1952   ASSERT_THAT(ReadPacket(snap), ElementsAre(FakePacketFragment(20, 'b')));
1953   ASSERT_THAT(ReadPacket(snap), ElementsAre(FakePacketFragment(30, 'c')));
1954   ASSERT_THAT(ReadPacket(snap), IsEmpty());
1955 }
1956 
TEST_F(TraceBufferTest,Clone_WithPatches)1957 TEST_F(TraceBufferTest, Clone_WithPatches) {
1958   ResetBuffer(4096);
1959   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
1960       .AddPacket(100, 'a')
1961       .CopyIntoTraceBuffer();
1962   CreateChunk(ProducerID(2), WriterID(1), ChunkID(0))
1963       .AddPacket(9, 'b')
1964       .ClearBytes(5, 4)  // 5 := 4th payload byte. Byte 0 is the varint header.
1965       .CopyIntoTraceBuffer();
1966   CreateChunk(ProducerID(3), WriterID(1), ChunkID(0))
1967       .AddPacket(100, 'c')
1968       .CopyIntoTraceBuffer();
1969   ASSERT_TRUE(TryPatchChunkContents(ProducerID(2), WriterID(1), ChunkID(0),
1970                                     {{5, {{'Y', 'M', 'C', 'A'}}}}));
1971 
1972   std::unique_ptr<TraceBuffer> snap = trace_buffer()->CloneReadOnly();
1973   snap->BeginRead();
1974   ASSERT_THAT(ReadPacket(snap), ElementsAre(FakePacketFragment(100, 'a')));
1975   ASSERT_THAT(ReadPacket(snap), ElementsAre(FakePacketFragment("b00-YMCA", 8)));
1976   ASSERT_THAT(ReadPacket(snap), ElementsAre(FakePacketFragment(100, 'c')));
1977   ASSERT_THAT(ReadPacket(snap), IsEmpty());
1978 }
1979 
TEST_F(TraceBufferTest,Clone_Wrapping)1980 TEST_F(TraceBufferTest, Clone_Wrapping) {
1981   ResetBuffer(4096);
1982   const size_t kFrgSize = 1024 - 16;  // For perfect wrapping every 4 fragments.
1983   for (WriterID i = 0; i < 6; i++) {
1984     CreateChunk(ProducerID(1), WriterID(i), ChunkID(0))
1985         .AddPacket(kFrgSize, static_cast<char>('a' + i))
1986         .CopyIntoTraceBuffer();
1987   }
1988   std::unique_ptr<TraceBuffer> snap = trace_buffer()->CloneReadOnly();
1989   ASSERT_EQ(snap->used_size(), snap->size());
1990   snap->BeginRead();
1991   ASSERT_THAT(ReadPacket(snap), ElementsAre(FakePacketFragment(kFrgSize, 'c')));
1992   ASSERT_THAT(ReadPacket(snap), ElementsAre(FakePacketFragment(kFrgSize, 'd')));
1993   ASSERT_THAT(ReadPacket(snap), ElementsAre(FakePacketFragment(kFrgSize, 'e')));
1994   ASSERT_THAT(ReadPacket(snap), ElementsAre(FakePacketFragment(kFrgSize, 'f')));
1995   ASSERT_THAT(ReadPacket(snap), IsEmpty());
1996 }
1997 
TEST_F(TraceBufferTest,Clone_WrappingWithPadding)1998 TEST_F(TraceBufferTest, Clone_WrappingWithPadding) {
1999   ResetBuffer(4096);
2000   // First create one 2KB chunk, so the contents are [aaaaaaaa00000000].
2001   CreateChunk(ProducerID(1), WriterID(0), ChunkID(0))
2002       .AddPacket(2048, static_cast<char>('a'))
2003       .CopyIntoTraceBuffer();
2004 
2005   // Then write a 3KB chunk that fits in the buffer, but requires zero padding
2006   // and restarting from the beginning, so the contents are [bbbbbbbbbbbb0000].
2007   CreateChunk(ProducerID(1), WriterID(1), ChunkID(0))
2008       .AddPacket(3192, static_cast<char>('b'))
2009       .CopyIntoTraceBuffer();
2010 
2011   ASSERT_EQ(trace_buffer()->used_size(), trace_buffer()->size());
2012   std::unique_ptr<TraceBuffer> snap = trace_buffer()->CloneReadOnly();
2013   ASSERT_EQ(snap->used_size(), snap->size());
2014   snap->BeginRead();
2015   ASSERT_THAT(ReadPacket(snap), ElementsAre(FakePacketFragment(3192, 'b')));
2016   ASSERT_THAT(ReadPacket(snap), IsEmpty());
2017 }
2018 
TEST_F(TraceBufferTest,Clone_CommitOnlyUsedSize)2019 TEST_F(TraceBufferTest, Clone_CommitOnlyUsedSize) {
2020   const size_t kPages = 32;
2021   const size_t page_size = base::GetSysPageSize();
2022   ResetBuffer(page_size * kPages);
2023   CreateChunk(ProducerID(1), WriterID(0), ChunkID(0))
2024       .AddPacket(1024, static_cast<char>('a'))
2025       .CopyIntoTraceBuffer();
2026 
2027   using base::vm_test_utils::IsMapped;
2028   auto is_only_first_page_mapped = [&](const TraceBuffer& buf) {
2029     bool first_mapped = IsMapped(GetBufData(buf), page_size);
2030     bool rest_mapped = IsMapped(GetBufData(buf) + page_size, kPages - 1);
2031     return first_mapped && !rest_mapped;
2032   };
2033 
2034   // If the test doesn't work as expected until here, there is no point checking
2035   // that the same assumptions hold true on the cloned buffer. Various platforms
2036   // can legitimately pre-fetch memory even if we don't page fault (also asan).
2037   if (!is_only_first_page_mapped(*trace_buffer()))
2038     GTEST_SKIP() << "VM commit detection not supported";
2039 
2040   std::unique_ptr<TraceBuffer> snap = trace_buffer()->CloneReadOnly();
2041   ASSERT_EQ(snap->used_size(), trace_buffer()->used_size());
2042   ASSERT_TRUE(is_only_first_page_mapped(*snap));
2043 }
2044 
2045 }  // namespace perfetto
2046