1*6777b538SAndroid Build Coastguard Worker // Copyright 2023 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "base/debug/allocation_trace.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <algorithm>
8*6777b538SAndroid Build Coastguard Worker #include <cstddef>
9*6777b538SAndroid Build Coastguard Worker #include <iterator>
10*6777b538SAndroid Build Coastguard Worker #include <memory>
11*6777b538SAndroid Build Coastguard Worker #include <sstream>
12*6777b538SAndroid Build Coastguard Worker #include <string>
13*6777b538SAndroid Build Coastguard Worker
14*6777b538SAndroid Build Coastguard Worker #include "base/allocator/dispatcher/dispatcher.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/allocator/dispatcher/testing/tools.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/debug/stack_trace.h"
17*6777b538SAndroid Build Coastguard Worker #include "partition_alloc/partition_alloc_allocation_data.h"
18*6777b538SAndroid Build Coastguard Worker #include "partition_alloc/partition_alloc_config.h"
19*6777b538SAndroid Build Coastguard Worker #include "testing/gmock/include/gmock/gmock-matchers.h"
20*6777b538SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
21*6777b538SAndroid Build Coastguard Worker
22*6777b538SAndroid Build Coastguard Worker using base::allocator::dispatcher::AllocationNotificationData;
23*6777b538SAndroid Build Coastguard Worker using base::allocator::dispatcher::AllocationSubsystem;
24*6777b538SAndroid Build Coastguard Worker using base::allocator::dispatcher::FreeNotificationData;
25*6777b538SAndroid Build Coastguard Worker using base::allocator::dispatcher::MTEMode;
26*6777b538SAndroid Build Coastguard Worker using testing::Combine;
27*6777b538SAndroid Build Coastguard Worker using testing::ContainerEq;
28*6777b538SAndroid Build Coastguard Worker using testing::Message;
29*6777b538SAndroid Build Coastguard Worker using testing::Test;
30*6777b538SAndroid Build Coastguard Worker using testing::Values;
31*6777b538SAndroid Build Coastguard Worker
32*6777b538SAndroid Build Coastguard Worker namespace base::debug::tracer {
33*6777b538SAndroid Build Coastguard Worker namespace {
34*6777b538SAndroid Build Coastguard Worker
35*6777b538SAndroid Build Coastguard Worker template <typename Iterator>
MakeString(Iterator begin,Iterator end)36*6777b538SAndroid Build Coastguard Worker std::string MakeString(Iterator begin, Iterator end) {
37*6777b538SAndroid Build Coastguard Worker using value_type = decltype(*begin);
38*6777b538SAndroid Build Coastguard Worker std::ostringstream oss;
39*6777b538SAndroid Build Coastguard Worker oss << '[';
40*6777b538SAndroid Build Coastguard Worker if (begin != end) {
41*6777b538SAndroid Build Coastguard Worker auto last_element = end - 1;
42*6777b538SAndroid Build Coastguard Worker std::copy(begin, last_element, std::ostream_iterator<value_type>(oss, ","));
43*6777b538SAndroid Build Coastguard Worker oss << *last_element;
44*6777b538SAndroid Build Coastguard Worker }
45*6777b538SAndroid Build Coastguard Worker oss << ']';
46*6777b538SAndroid Build Coastguard Worker
47*6777b538SAndroid Build Coastguard Worker return oss.str();
48*6777b538SAndroid Build Coastguard Worker }
49*6777b538SAndroid Build Coastguard Worker
50*6777b538SAndroid Build Coastguard Worker template <typename C>
MakeString(const C & data)51*6777b538SAndroid Build Coastguard Worker std::string MakeString(const C& data) {
52*6777b538SAndroid Build Coastguard Worker return MakeString(std::begin(data), std::end(data));
53*6777b538SAndroid Build Coastguard Worker }
54*6777b538SAndroid Build Coastguard Worker
AreEqual(const base::debug::tracer::OperationRecord & expected,const base::debug::tracer::OperationRecord & is)55*6777b538SAndroid Build Coastguard Worker void AreEqual(const base::debug::tracer::OperationRecord& expected,
56*6777b538SAndroid Build Coastguard Worker const base::debug::tracer::OperationRecord& is) {
57*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(is.GetOperationType(), expected.GetOperationType());
58*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(is.GetAddress(), expected.GetAddress());
59*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(is.GetSize(), expected.GetSize());
60*6777b538SAndroid Build Coastguard Worker EXPECT_THAT(is.GetStackTrace(), ContainerEq(expected.GetStackTrace()));
61*6777b538SAndroid Build Coastguard Worker }
62*6777b538SAndroid Build Coastguard Worker
63*6777b538SAndroid Build Coastguard Worker } // namespace
64*6777b538SAndroid Build Coastguard Worker
65*6777b538SAndroid Build Coastguard Worker class AllocationTraceRecorderTest : public Test {
66*6777b538SAndroid Build Coastguard Worker protected:
GetSubjectUnderTest() const67*6777b538SAndroid Build Coastguard Worker AllocationTraceRecorder& GetSubjectUnderTest() const {
68*6777b538SAndroid Build Coastguard Worker return *subject_under_test_;
69*6777b538SAndroid Build Coastguard Worker }
70*6777b538SAndroid Build Coastguard Worker // During test, Buffer will hold a binary copy of the AllocationTraceRecorder
71*6777b538SAndroid Build Coastguard Worker // under test.
72*6777b538SAndroid Build Coastguard Worker struct Buffer {
73*6777b538SAndroid Build Coastguard Worker alignas(
74*6777b538SAndroid Build Coastguard Worker AllocationTraceRecorder) uint8_t data[sizeof(AllocationTraceRecorder)];
75*6777b538SAndroid Build Coastguard Worker };
76*6777b538SAndroid Build Coastguard Worker
77*6777b538SAndroid Build Coastguard Worker protected:
CreateAllocationData(void * address,size_t size,MTEMode mte_mode=MTEMode::kUndefined)78*6777b538SAndroid Build Coastguard Worker AllocationNotificationData CreateAllocationData(
79*6777b538SAndroid Build Coastguard Worker void* address,
80*6777b538SAndroid Build Coastguard Worker size_t size,
81*6777b538SAndroid Build Coastguard Worker MTEMode mte_mode = MTEMode::kUndefined) {
82*6777b538SAndroid Build Coastguard Worker return AllocationNotificationData(address, size, nullptr,
83*6777b538SAndroid Build Coastguard Worker AllocationSubsystem::kPartitionAllocator)
84*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(HAS_MEMORY_TAGGING)
85*6777b538SAndroid Build Coastguard Worker .SetMteReportingMode(mte_mode)
86*6777b538SAndroid Build Coastguard Worker #endif
87*6777b538SAndroid Build Coastguard Worker ;
88*6777b538SAndroid Build Coastguard Worker }
89*6777b538SAndroid Build Coastguard Worker
CreateFreeData(void * address,MTEMode mte_mode=MTEMode::kUndefined)90*6777b538SAndroid Build Coastguard Worker FreeNotificationData CreateFreeData(void* address,
91*6777b538SAndroid Build Coastguard Worker MTEMode mte_mode = MTEMode::kUndefined) {
92*6777b538SAndroid Build Coastguard Worker return FreeNotificationData(address,
93*6777b538SAndroid Build Coastguard Worker AllocationSubsystem::kPartitionAllocator)
94*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(HAS_MEMORY_TAGGING)
95*6777b538SAndroid Build Coastguard Worker .SetMteReportingMode(mte_mode)
96*6777b538SAndroid Build Coastguard Worker #endif
97*6777b538SAndroid Build Coastguard Worker ;
98*6777b538SAndroid Build Coastguard Worker }
99*6777b538SAndroid Build Coastguard Worker
100*6777b538SAndroid Build Coastguard Worker private:
101*6777b538SAndroid Build Coastguard Worker // The recorder under test. Depending on number and size of traces, it
102*6777b538SAndroid Build Coastguard Worker // requires quite a lot of space. Therefore, we create it on heap to avoid any
103*6777b538SAndroid Build Coastguard Worker // out-of-stack scenarios.
104*6777b538SAndroid Build Coastguard Worker std::unique_ptr<AllocationTraceRecorder> const subject_under_test_ =
105*6777b538SAndroid Build Coastguard Worker std::make_unique<AllocationTraceRecorder>();
106*6777b538SAndroid Build Coastguard Worker };
107*6777b538SAndroid Build Coastguard Worker
TEST_F(AllocationTraceRecorderTest,VerifyBinaryCopy)108*6777b538SAndroid Build Coastguard Worker TEST_F(AllocationTraceRecorderTest, VerifyBinaryCopy) {
109*6777b538SAndroid Build Coastguard Worker AllocationTraceRecorder& subject_under_test = GetSubjectUnderTest();
110*6777b538SAndroid Build Coastguard Worker
111*6777b538SAndroid Build Coastguard Worker // Fill the recorder with some fake allocations and frees.
112*6777b538SAndroid Build Coastguard Worker constexpr size_t number_of_records = 100;
113*6777b538SAndroid Build Coastguard Worker
114*6777b538SAndroid Build Coastguard Worker for (size_t index = 0; index < number_of_records; ++index) {
115*6777b538SAndroid Build Coastguard Worker if (index & 0x1) {
116*6777b538SAndroid Build Coastguard Worker subject_under_test.OnAllocation(
117*6777b538SAndroid Build Coastguard Worker CreateAllocationData(this, sizeof(*this)));
118*6777b538SAndroid Build Coastguard Worker } else {
119*6777b538SAndroid Build Coastguard Worker subject_under_test.OnFree(CreateFreeData(this));
120*6777b538SAndroid Build Coastguard Worker }
121*6777b538SAndroid Build Coastguard Worker }
122*6777b538SAndroid Build Coastguard Worker
123*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(number_of_records, subject_under_test.size());
124*6777b538SAndroid Build Coastguard Worker
125*6777b538SAndroid Build Coastguard Worker // Create a copy of the recorder using buffer as storage for the copy.
126*6777b538SAndroid Build Coastguard Worker auto const buffer = std::make_unique<Buffer>();
127*6777b538SAndroid Build Coastguard Worker
128*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(buffer);
129*6777b538SAndroid Build Coastguard Worker
130*6777b538SAndroid Build Coastguard Worker auto* const buffered_recorder =
131*6777b538SAndroid Build Coastguard Worker reinterpret_cast<AllocationTraceRecorder*>(&(buffer->data[0]));
132*6777b538SAndroid Build Coastguard Worker
133*6777b538SAndroid Build Coastguard Worker memcpy(buffered_recorder, &subject_under_test,
134*6777b538SAndroid Build Coastguard Worker sizeof(AllocationTraceRecorder));
135*6777b538SAndroid Build Coastguard Worker
136*6777b538SAndroid Build Coastguard Worker // Verify that the original recorder and the buffered recorder are equal.
137*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(subject_under_test.size(), buffered_recorder->size());
138*6777b538SAndroid Build Coastguard Worker
139*6777b538SAndroid Build Coastguard Worker for (size_t index = 0; index < subject_under_test.size(); ++index) {
140*6777b538SAndroid Build Coastguard Worker SCOPED_TRACE(Message("difference detected at index ") << index);
141*6777b538SAndroid Build Coastguard Worker AreEqual(subject_under_test[index], (*buffered_recorder)[index]);
142*6777b538SAndroid Build Coastguard Worker }
143*6777b538SAndroid Build Coastguard Worker }
144*6777b538SAndroid Build Coastguard Worker
TEST_F(AllocationTraceRecorderTest,VerifySingleAllocation)145*6777b538SAndroid Build Coastguard Worker TEST_F(AllocationTraceRecorderTest, VerifySingleAllocation) {
146*6777b538SAndroid Build Coastguard Worker AllocationTraceRecorder& subject_under_test = GetSubjectUnderTest();
147*6777b538SAndroid Build Coastguard Worker
148*6777b538SAndroid Build Coastguard Worker subject_under_test.OnAllocation(
149*6777b538SAndroid Build Coastguard Worker CreateAllocationData(&subject_under_test, sizeof(subject_under_test)));
150*6777b538SAndroid Build Coastguard Worker
151*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(1ul, subject_under_test.size());
152*6777b538SAndroid Build Coastguard Worker
153*6777b538SAndroid Build Coastguard Worker const auto& record_data = subject_under_test[0];
154*6777b538SAndroid Build Coastguard Worker const auto& stack_trace = record_data.GetStackTrace();
155*6777b538SAndroid Build Coastguard Worker
156*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(OperationType::kAllocation, record_data.GetOperationType());
157*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(&subject_under_test, record_data.GetAddress());
158*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(sizeof(subject_under_test), record_data.GetSize());
159*6777b538SAndroid Build Coastguard Worker EXPECT_NE(nullptr, stack_trace.at(0));
160*6777b538SAndroid Build Coastguard Worker }
161*6777b538SAndroid Build Coastguard Worker
TEST_F(AllocationTraceRecorderTest,VerifySingleFree)162*6777b538SAndroid Build Coastguard Worker TEST_F(AllocationTraceRecorderTest, VerifySingleFree) {
163*6777b538SAndroid Build Coastguard Worker AllocationTraceRecorder& subject_under_test = GetSubjectUnderTest();
164*6777b538SAndroid Build Coastguard Worker
165*6777b538SAndroid Build Coastguard Worker subject_under_test.OnFree(CreateFreeData(&subject_under_test));
166*6777b538SAndroid Build Coastguard Worker
167*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(1ul, subject_under_test.size());
168*6777b538SAndroid Build Coastguard Worker
169*6777b538SAndroid Build Coastguard Worker const auto& record_data = subject_under_test[0];
170*6777b538SAndroid Build Coastguard Worker const auto& stack_trace = record_data.GetStackTrace();
171*6777b538SAndroid Build Coastguard Worker
172*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(OperationType::kFree, record_data.GetOperationType());
173*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(&subject_under_test, record_data.GetAddress());
174*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(0ul, record_data.GetSize());
175*6777b538SAndroid Build Coastguard Worker EXPECT_NE(nullptr, stack_trace.at(0));
176*6777b538SAndroid Build Coastguard Worker }
177*6777b538SAndroid Build Coastguard Worker
TEST_F(AllocationTraceRecorderTest,VerifyMultipleOperations)178*6777b538SAndroid Build Coastguard Worker TEST_F(AllocationTraceRecorderTest, VerifyMultipleOperations) {
179*6777b538SAndroid Build Coastguard Worker AllocationTraceRecorder& subject_under_test = GetSubjectUnderTest();
180*6777b538SAndroid Build Coastguard Worker
181*6777b538SAndroid Build Coastguard Worker // We perform a number of operations.
182*6777b538SAndroid Build Coastguard Worker subject_under_test.OnAllocation(
183*6777b538SAndroid Build Coastguard Worker CreateAllocationData(this, 1 * sizeof(*this)));
184*6777b538SAndroid Build Coastguard Worker subject_under_test.OnFree(CreateFreeData(this + 2));
185*6777b538SAndroid Build Coastguard Worker subject_under_test.OnAllocation(
186*6777b538SAndroid Build Coastguard Worker CreateAllocationData(this + 3, 3 * sizeof(*this)));
187*6777b538SAndroid Build Coastguard Worker subject_under_test.OnAllocation(
188*6777b538SAndroid Build Coastguard Worker CreateAllocationData(this + 4, 4 * sizeof(*this)));
189*6777b538SAndroid Build Coastguard Worker subject_under_test.OnFree(CreateFreeData(this + 5));
190*6777b538SAndroid Build Coastguard Worker subject_under_test.OnFree(CreateFreeData(this + 6));
191*6777b538SAndroid Build Coastguard Worker
192*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(subject_under_test.size(), 6ul);
193*6777b538SAndroid Build Coastguard Worker
194*6777b538SAndroid Build Coastguard Worker // Verify that the stored operations match the expected.
195*6777b538SAndroid Build Coastguard Worker {
196*6777b538SAndroid Build Coastguard Worker const auto& entry = subject_under_test[0];
197*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(entry.GetOperationType(), OperationType::kAllocation);
198*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(entry.GetAddress(), this);
199*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(entry.GetSize(), 1 * sizeof(*this));
200*6777b538SAndroid Build Coastguard Worker ASSERT_NE(entry.GetStackTrace()[0], nullptr);
201*6777b538SAndroid Build Coastguard Worker }
202*6777b538SAndroid Build Coastguard Worker {
203*6777b538SAndroid Build Coastguard Worker const auto& entry = subject_under_test[1];
204*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(entry.GetOperationType(), OperationType::kFree);
205*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(entry.GetAddress(), (this + 2));
206*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(entry.GetSize(), 0ul);
207*6777b538SAndroid Build Coastguard Worker ASSERT_NE(entry.GetStackTrace()[0], nullptr);
208*6777b538SAndroid Build Coastguard Worker }
209*6777b538SAndroid Build Coastguard Worker {
210*6777b538SAndroid Build Coastguard Worker const auto& entry = subject_under_test[2];
211*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(entry.GetOperationType(), OperationType::kAllocation);
212*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(entry.GetAddress(), (this + 3));
213*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(entry.GetSize(), 3 * sizeof(*this));
214*6777b538SAndroid Build Coastguard Worker ASSERT_NE(entry.GetStackTrace()[0], nullptr);
215*6777b538SAndroid Build Coastguard Worker }
216*6777b538SAndroid Build Coastguard Worker {
217*6777b538SAndroid Build Coastguard Worker const auto& entry = subject_under_test[3];
218*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(entry.GetOperationType(), OperationType::kAllocation);
219*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(entry.GetAddress(), (this + 4));
220*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(entry.GetSize(), 4 * sizeof(*this));
221*6777b538SAndroid Build Coastguard Worker ASSERT_NE(entry.GetStackTrace()[0], nullptr);
222*6777b538SAndroid Build Coastguard Worker }
223*6777b538SAndroid Build Coastguard Worker {
224*6777b538SAndroid Build Coastguard Worker const auto& entry = subject_under_test[4];
225*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(entry.GetOperationType(), OperationType::kFree);
226*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(entry.GetAddress(), (this + 5));
227*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(entry.GetSize(), 0ul);
228*6777b538SAndroid Build Coastguard Worker ASSERT_NE(entry.GetStackTrace()[0], nullptr);
229*6777b538SAndroid Build Coastguard Worker }
230*6777b538SAndroid Build Coastguard Worker {
231*6777b538SAndroid Build Coastguard Worker const auto& entry = subject_under_test[5];
232*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(entry.GetOperationType(), OperationType::kFree);
233*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(entry.GetAddress(), (this + 6));
234*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(entry.GetSize(), 0ul);
235*6777b538SAndroid Build Coastguard Worker ASSERT_NE(entry.GetStackTrace()[0], nullptr);
236*6777b538SAndroid Build Coastguard Worker }
237*6777b538SAndroid Build Coastguard Worker }
238*6777b538SAndroid Build Coastguard Worker
TEST_F(AllocationTraceRecorderTest,VerifyOverflowOfOperations)239*6777b538SAndroid Build Coastguard Worker TEST_F(AllocationTraceRecorderTest, VerifyOverflowOfOperations) {
240*6777b538SAndroid Build Coastguard Worker AllocationTraceRecorder& subject_under_test = GetSubjectUnderTest();
241*6777b538SAndroid Build Coastguard Worker
242*6777b538SAndroid Build Coastguard Worker decltype(subject_under_test.GetMaximumNumberOfTraces()) idx;
243*6777b538SAndroid Build Coastguard Worker for (idx = 0; idx < subject_under_test.GetMaximumNumberOfTraces(); ++idx) {
244*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(subject_under_test.size(), idx);
245*6777b538SAndroid Build Coastguard Worker const bool is_allocation = !(idx & 0x1);
246*6777b538SAndroid Build Coastguard Worker
247*6777b538SAndroid Build Coastguard Worker // Record an allocation or free.
248*6777b538SAndroid Build Coastguard Worker if (is_allocation) {
249*6777b538SAndroid Build Coastguard Worker subject_under_test.OnAllocation(CreateAllocationData(this + idx, idx));
250*6777b538SAndroid Build Coastguard Worker } else {
251*6777b538SAndroid Build Coastguard Worker subject_under_test.OnFree(CreateFreeData(this + idx));
252*6777b538SAndroid Build Coastguard Worker }
253*6777b538SAndroid Build Coastguard Worker
254*6777b538SAndroid Build Coastguard Worker // Some verifications.
255*6777b538SAndroid Build Coastguard Worker {
256*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(subject_under_test.size(), (idx + 1));
257*6777b538SAndroid Build Coastguard Worker
258*6777b538SAndroid Build Coastguard Worker // Some verification on the added entry.
259*6777b538SAndroid Build Coastguard Worker {
260*6777b538SAndroid Build Coastguard Worker const auto& last_entry = subject_under_test[idx];
261*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(last_entry.GetAddress(), (this + idx));
262*6777b538SAndroid Build Coastguard Worker // No full verification intended, just a check that something has been
263*6777b538SAndroid Build Coastguard Worker // written.
264*6777b538SAndroid Build Coastguard Worker ASSERT_NE(last_entry.GetStackTrace()[0], nullptr);
265*6777b538SAndroid Build Coastguard Worker if (is_allocation) {
266*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(last_entry.GetOperationType(), OperationType::kAllocation);
267*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(last_entry.GetSize(), idx);
268*6777b538SAndroid Build Coastguard Worker } else {
269*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(last_entry.GetOperationType(), OperationType::kFree);
270*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(last_entry.GetSize(), 0ul);
271*6777b538SAndroid Build Coastguard Worker }
272*6777b538SAndroid Build Coastguard Worker }
273*6777b538SAndroid Build Coastguard Worker
274*6777b538SAndroid Build Coastguard Worker // No changes on the first entry must be done.
275*6777b538SAndroid Build Coastguard Worker {
276*6777b538SAndroid Build Coastguard Worker const auto& first_entry = subject_under_test[0];
277*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(first_entry.GetOperationType(), OperationType::kAllocation);
278*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(first_entry.GetAddress(), this);
279*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(first_entry.GetSize(), 0ul);
280*6777b538SAndroid Build Coastguard Worker }
281*6777b538SAndroid Build Coastguard Worker }
282*6777b538SAndroid Build Coastguard Worker }
283*6777b538SAndroid Build Coastguard Worker
284*6777b538SAndroid Build Coastguard Worker // By now we have written all available records including the last one.
285*6777b538SAndroid Build Coastguard Worker // So the following allocation should overwrite the first record.
286*6777b538SAndroid Build Coastguard Worker {
287*6777b538SAndroid Build Coastguard Worker const auto& old_second_entry = subject_under_test[1];
288*6777b538SAndroid Build Coastguard Worker
289*6777b538SAndroid Build Coastguard Worker subject_under_test.OnAllocation(CreateAllocationData(this + idx, idx));
290*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(subject_under_test.size(),
291*6777b538SAndroid Build Coastguard Worker subject_under_test.GetMaximumNumberOfTraces());
292*6777b538SAndroid Build Coastguard Worker const auto& last_entry =
293*6777b538SAndroid Build Coastguard Worker subject_under_test[subject_under_test.GetMaximumNumberOfTraces() - 1];
294*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(last_entry.GetOperationType(), OperationType::kAllocation);
295*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(last_entry.GetAddress(), (this + idx));
296*6777b538SAndroid Build Coastguard Worker
297*6777b538SAndroid Build Coastguard Worker // Check that the previous first entry (an allocation) is gone. Accessing
298*6777b538SAndroid Build Coastguard Worker // the first record now yields what was previously the second record (a free
299*6777b538SAndroid Build Coastguard Worker // operation).
300*6777b538SAndroid Build Coastguard Worker const auto& first_entry = subject_under_test[0];
301*6777b538SAndroid Build Coastguard Worker
302*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(&old_second_entry, &first_entry);
303*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(first_entry.GetOperationType(), OperationType::kFree);
304*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(first_entry.GetAddress(), (this + 1));
305*6777b538SAndroid Build Coastguard Worker }
306*6777b538SAndroid Build Coastguard Worker }
307*6777b538SAndroid Build Coastguard Worker
TEST_F(AllocationTraceRecorderTest,VerifyWithHooks)308*6777b538SAndroid Build Coastguard Worker TEST_F(AllocationTraceRecorderTest, VerifyWithHooks) {
309*6777b538SAndroid Build Coastguard Worker auto& dispatcher = base::allocator::dispatcher::Dispatcher::GetInstance();
310*6777b538SAndroid Build Coastguard Worker AllocationTraceRecorder& subject_under_test = GetSubjectUnderTest();
311*6777b538SAndroid Build Coastguard Worker
312*6777b538SAndroid Build Coastguard Worker dispatcher.InitializeForTesting(&subject_under_test);
313*6777b538SAndroid Build Coastguard Worker
314*6777b538SAndroid Build Coastguard Worker // Perform an allocation and free.
315*6777b538SAndroid Build Coastguard Worker std::make_unique<std::string>(
316*6777b538SAndroid Build Coastguard Worker "Just enforce an allocation and free to trigger notification of the "
317*6777b538SAndroid Build Coastguard Worker "subject under test. Hopefully this string is long enough to bypass any "
318*6777b538SAndroid Build Coastguard Worker "small string optimizations that the STL implementation might use.");
319*6777b538SAndroid Build Coastguard Worker
320*6777b538SAndroid Build Coastguard Worker dispatcher.ResetForTesting();
321*6777b538SAndroid Build Coastguard Worker
322*6777b538SAndroid Build Coastguard Worker // We only test for greater-equal since allocation from other parts of GTest
323*6777b538SAndroid Build Coastguard Worker // might have interfered.
324*6777b538SAndroid Build Coastguard Worker EXPECT_GE(subject_under_test.size(), 2ul);
325*6777b538SAndroid Build Coastguard Worker }
326*6777b538SAndroid Build Coastguard Worker
327*6777b538SAndroid Build Coastguard Worker class OperationRecordTest : public Test {
328*6777b538SAndroid Build Coastguard Worker protected:
329*6777b538SAndroid Build Coastguard Worker using ReferenceStackTrace = std::vector<const void*>;
330*6777b538SAndroid Build Coastguard Worker
GetReferenceTrace()331*6777b538SAndroid Build Coastguard Worker ReferenceStackTrace GetReferenceTrace() {
332*6777b538SAndroid Build Coastguard Worker constexpr size_t max_trace_size = 128;
333*6777b538SAndroid Build Coastguard Worker const void* frame_pointers[max_trace_size]{nullptr};
334*6777b538SAndroid Build Coastguard Worker const auto num_frames = base::debug::TraceStackFramePointers(
335*6777b538SAndroid Build Coastguard Worker &frame_pointers[0], max_trace_size, 0);
336*6777b538SAndroid Build Coastguard Worker ReferenceStackTrace trace;
337*6777b538SAndroid Build Coastguard Worker std::copy_n(std::begin(frame_pointers), num_frames,
338*6777b538SAndroid Build Coastguard Worker std::back_inserter(trace));
339*6777b538SAndroid Build Coastguard Worker return trace;
340*6777b538SAndroid Build Coastguard Worker }
341*6777b538SAndroid Build Coastguard Worker
VerifyStackTrace(const ReferenceStackTrace & reference_stack_trace,const base::debug::tracer::StackTraceContainer & stack_trace)342*6777b538SAndroid Build Coastguard Worker void VerifyStackTrace(
343*6777b538SAndroid Build Coastguard Worker const ReferenceStackTrace& reference_stack_trace,
344*6777b538SAndroid Build Coastguard Worker const base::debug::tracer::StackTraceContainer& stack_trace) {
345*6777b538SAndroid Build Coastguard Worker // Verify we have at least one entry in the stack.
346*6777b538SAndroid Build Coastguard Worker ASSERT_NE(nullptr, stack_trace.at(0));
347*6777b538SAndroid Build Coastguard Worker ASSERT_GT(stack_trace.size(), 0ul);
348*6777b538SAndroid Build Coastguard Worker
349*6777b538SAndroid Build Coastguard Worker // Although functions are marked ALWAYS_INLINE, the compiler may choose not
350*6777b538SAndroid Build Coastguard Worker // to inline, depending i.e. on the optimization level. Therefore, we search
351*6777b538SAndroid Build Coastguard Worker // for the first common frame in both stack-traces. From there on, both must
352*6777b538SAndroid Build Coastguard Worker // be equal for the remaining number of frames.
353*6777b538SAndroid Build Coastguard Worker auto const it_stack_trace_begin = std::begin(stack_trace);
354*6777b538SAndroid Build Coastguard Worker auto const it_stack_trace_end =
355*6777b538SAndroid Build Coastguard Worker std::find(it_stack_trace_begin, std::end(stack_trace), nullptr);
356*6777b538SAndroid Build Coastguard Worker auto const it_reference_stack_trace_end = std::end(reference_stack_trace);
357*6777b538SAndroid Build Coastguard Worker
358*6777b538SAndroid Build Coastguard Worker auto const it_stack_trace = std::find_first_of(
359*6777b538SAndroid Build Coastguard Worker it_stack_trace_begin, it_stack_trace_end,
360*6777b538SAndroid Build Coastguard Worker std::begin(reference_stack_trace), it_reference_stack_trace_end);
361*6777b538SAndroid Build Coastguard Worker
362*6777b538SAndroid Build Coastguard Worker ASSERT_NE(it_stack_trace, it_stack_trace_end)
363*6777b538SAndroid Build Coastguard Worker << "stack-trace and reference-stack-trace share no common frame!\n"
364*6777b538SAndroid Build Coastguard Worker << "stack trace = " << MakeString(stack_trace) << '\n'
365*6777b538SAndroid Build Coastguard Worker << "reference stack trace = " << MakeString(reference_stack_trace);
366*6777b538SAndroid Build Coastguard Worker
367*6777b538SAndroid Build Coastguard Worker // Find the common frame in the reference-stack-trace.
368*6777b538SAndroid Build Coastguard Worker const auto it_reference_stack_trace =
369*6777b538SAndroid Build Coastguard Worker std::find(std::begin(reference_stack_trace),
370*6777b538SAndroid Build Coastguard Worker it_reference_stack_trace_end, *it_stack_trace);
371*6777b538SAndroid Build Coastguard Worker
372*6777b538SAndroid Build Coastguard Worker const auto number_of_expected_common_frames = std::min(
373*6777b538SAndroid Build Coastguard Worker std::distance(it_stack_trace, it_stack_trace_end),
374*6777b538SAndroid Build Coastguard Worker std::distance(it_reference_stack_trace, it_reference_stack_trace_end));
375*6777b538SAndroid Build Coastguard Worker
376*6777b538SAndroid Build Coastguard Worker // Check if we have any difference within the section of frames that we
377*6777b538SAndroid Build Coastguard Worker // expect to be equal.
378*6777b538SAndroid Build Coastguard Worker const auto mismatch = std::mismatch(
379*6777b538SAndroid Build Coastguard Worker it_reference_stack_trace,
380*6777b538SAndroid Build Coastguard Worker it_reference_stack_trace + number_of_expected_common_frames,
381*6777b538SAndroid Build Coastguard Worker it_stack_trace);
382*6777b538SAndroid Build Coastguard Worker
383*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(mismatch.first,
384*6777b538SAndroid Build Coastguard Worker (it_reference_stack_trace + number_of_expected_common_frames))
385*6777b538SAndroid Build Coastguard Worker << "found difference in the range of frames expected to be equal!\n"
386*6777b538SAndroid Build Coastguard Worker << "position = "
387*6777b538SAndroid Build Coastguard Worker << std::distance(it_reference_stack_trace, mismatch.first) << '\n'
388*6777b538SAndroid Build Coastguard Worker << "stack trace = "
389*6777b538SAndroid Build Coastguard Worker << MakeString(it_stack_trace,
390*6777b538SAndroid Build Coastguard Worker it_stack_trace + number_of_expected_common_frames)
391*6777b538SAndroid Build Coastguard Worker << '\n'
392*6777b538SAndroid Build Coastguard Worker << "reference stack trace = "
393*6777b538SAndroid Build Coastguard Worker << MakeString(
394*6777b538SAndroid Build Coastguard Worker it_reference_stack_trace,
395*6777b538SAndroid Build Coastguard Worker it_reference_stack_trace + number_of_expected_common_frames);
396*6777b538SAndroid Build Coastguard Worker }
397*6777b538SAndroid Build Coastguard Worker };
398*6777b538SAndroid Build Coastguard Worker
TEST_F(OperationRecordTest,VerifyConstructor)399*6777b538SAndroid Build Coastguard Worker TEST_F(OperationRecordTest, VerifyConstructor) {
400*6777b538SAndroid Build Coastguard Worker OperationRecord subject_under_test;
401*6777b538SAndroid Build Coastguard Worker
402*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(subject_under_test.GetOperationType(), OperationType::kNone);
403*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(subject_under_test.GetAddress(), nullptr);
404*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(subject_under_test.GetSize(), 0ul);
405*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(subject_under_test.IsRecording());
406*6777b538SAndroid Build Coastguard Worker
407*6777b538SAndroid Build Coastguard Worker // The stack trace is not initialized by the constructor. Therefore, we do not
408*6777b538SAndroid Build Coastguard Worker // check here.
409*6777b538SAndroid Build Coastguard Worker }
410*6777b538SAndroid Build Coastguard Worker
TEST_F(OperationRecordTest,VerifyRecordAllocation)411*6777b538SAndroid Build Coastguard Worker TEST_F(OperationRecordTest, VerifyRecordAllocation) {
412*6777b538SAndroid Build Coastguard Worker const ReferenceStackTrace reference_trace = GetReferenceTrace();
413*6777b538SAndroid Build Coastguard Worker
414*6777b538SAndroid Build Coastguard Worker void* const address = this;
415*6777b538SAndroid Build Coastguard Worker size_t const size = sizeof(*this);
416*6777b538SAndroid Build Coastguard Worker
417*6777b538SAndroid Build Coastguard Worker OperationRecord subject_under_test;
418*6777b538SAndroid Build Coastguard Worker
419*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(subject_under_test.InitializeAllocation(address, size));
420*6777b538SAndroid Build Coastguard Worker
421*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(OperationType::kAllocation, subject_under_test.GetOperationType());
422*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(address, subject_under_test.GetAddress());
423*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(size, subject_under_test.GetSize());
424*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(subject_under_test.IsRecording());
425*6777b538SAndroid Build Coastguard Worker
426*6777b538SAndroid Build Coastguard Worker VerifyStackTrace(reference_trace, subject_under_test.GetStackTrace());
427*6777b538SAndroid Build Coastguard Worker }
428*6777b538SAndroid Build Coastguard Worker
TEST_F(OperationRecordTest,VerifyRecordFree)429*6777b538SAndroid Build Coastguard Worker TEST_F(OperationRecordTest, VerifyRecordFree) {
430*6777b538SAndroid Build Coastguard Worker const ReferenceStackTrace reference_trace = GetReferenceTrace();
431*6777b538SAndroid Build Coastguard Worker
432*6777b538SAndroid Build Coastguard Worker void* const address = this;
433*6777b538SAndroid Build Coastguard Worker size_t const size = 0;
434*6777b538SAndroid Build Coastguard Worker
435*6777b538SAndroid Build Coastguard Worker OperationRecord subject_under_test;
436*6777b538SAndroid Build Coastguard Worker
437*6777b538SAndroid Build Coastguard Worker ASSERT_TRUE(subject_under_test.InitializeFree(address));
438*6777b538SAndroid Build Coastguard Worker
439*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(OperationType::kFree, subject_under_test.GetOperationType());
440*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(address, subject_under_test.GetAddress());
441*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(size, subject_under_test.GetSize());
442*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(subject_under_test.IsRecording());
443*6777b538SAndroid Build Coastguard Worker
444*6777b538SAndroid Build Coastguard Worker VerifyStackTrace(reference_trace, subject_under_test.GetStackTrace());
445*6777b538SAndroid Build Coastguard Worker }
446*6777b538SAndroid Build Coastguard Worker
447*6777b538SAndroid Build Coastguard Worker } // namespace base::debug::tracer
448