xref: /aosp_15_r20/external/pigweed/pw_malloc/malloc_test.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker // Copyright 2024 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker //     https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker 
15*61c4878aSAndroid Build Coastguard Worker #include "pw_malloc/malloc.h"
16*61c4878aSAndroid Build Coastguard Worker 
17*61c4878aSAndroid Build Coastguard Worker #include <cstdint>
18*61c4878aSAndroid Build Coastguard Worker 
19*61c4878aSAndroid Build Coastguard Worker #include "pw_tokenizer/detokenize.h"
20*61c4878aSAndroid Build Coastguard Worker #include "pw_unit_test/framework.h"
21*61c4878aSAndroid Build Coastguard Worker 
22*61c4878aSAndroid Build Coastguard Worker namespace {
23*61c4878aSAndroid Build Coastguard Worker 
24*61c4878aSAndroid Build Coastguard Worker using namespace std::literals::string_view_literals;
25*61c4878aSAndroid Build Coastguard Worker 
26*61c4878aSAndroid Build Coastguard Worker std::array<std::byte, 8192> system_heap;
27*61c4878aSAndroid Build Coastguard Worker 
28*61c4878aSAndroid Build Coastguard Worker class MallocTest : public ::pw::unit_test::internal::Test {
29*61c4878aSAndroid Build Coastguard Worker  public:
30*61c4878aSAndroid Build Coastguard Worker   // NOTE! This tests should only be run WITHOUT a pw_malloc backend set.
31*61c4878aSAndroid Build Coastguard Worker   // Otherwise, `InitSystemAllocator` may have already been called and may
32*61c4878aSAndroid Build Coastguard Worker   // crash.
SetUpTestSuite()33*61c4878aSAndroid Build Coastguard Worker   static void SetUpTestSuite() { pw::malloc::InitSystemAllocator(system_heap); }
34*61c4878aSAndroid Build Coastguard Worker 
35*61c4878aSAndroid Build Coastguard Worker  protected:
36*61c4878aSAndroid Build Coastguard Worker   // NOTE!! This tests ONLY run on host with the "light" framework. Other
37*61c4878aSAndroid Build Coastguard Worker   // test frameworks may attempt and fail to de/allocate outside the test method
38*61c4878aSAndroid Build Coastguard Worker   // outside the test body.
SetUp()39*61c4878aSAndroid Build Coastguard Worker   void SetUp() override {
40*61c4878aSAndroid Build Coastguard Worker     auto& system_metrics = pw::malloc::GetSystemMetrics();
41*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(system_metrics.allocated_bytes.value(), 0U);
42*61c4878aSAndroid Build Coastguard Worker   }
43*61c4878aSAndroid Build Coastguard Worker 
TearDown()44*61c4878aSAndroid Build Coastguard Worker   void TearDown() override {
45*61c4878aSAndroid Build Coastguard Worker     auto& system_metrics = pw::malloc::GetSystemMetrics();
46*61c4878aSAndroid Build Coastguard Worker     ASSERT_EQ(system_metrics.allocated_bytes.value(), 0U);
47*61c4878aSAndroid Build Coastguard Worker   }
48*61c4878aSAndroid Build Coastguard Worker };
49*61c4878aSAndroid Build Coastguard Worker 
TEST_F(MallocTest,MallocFree)50*61c4878aSAndroid Build Coastguard Worker TEST_F(MallocTest, MallocFree) {
51*61c4878aSAndroid Build Coastguard Worker   constexpr size_t kSize = 256;
52*61c4878aSAndroid Build Coastguard Worker   auto& system_metrics = pw::malloc::GetSystemMetrics();
53*61c4878aSAndroid Build Coastguard Worker 
54*61c4878aSAndroid Build Coastguard Worker   void* ptr = malloc(kSize);
55*61c4878aSAndroid Build Coastguard Worker   ASSERT_NE(ptr, nullptr);
56*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(system_metrics.requested_bytes.value(), kSize);
57*61c4878aSAndroid Build Coastguard Worker 
58*61c4878aSAndroid Build Coastguard Worker   free(ptr);
59*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(system_metrics.allocated_bytes.value(), 0U);
60*61c4878aSAndroid Build Coastguard Worker }
61*61c4878aSAndroid Build Coastguard Worker 
TEST_F(MallocTest,NewDelete)62*61c4878aSAndroid Build Coastguard Worker TEST_F(MallocTest, NewDelete) {
63*61c4878aSAndroid Build Coastguard Worker   constexpr size_t kSize = 256;
64*61c4878aSAndroid Build Coastguard Worker   auto& system_metrics = pw::malloc::GetSystemMetrics();
65*61c4878aSAndroid Build Coastguard Worker 
66*61c4878aSAndroid Build Coastguard Worker   auto* ptr = new std::array<std::byte, kSize>();
67*61c4878aSAndroid Build Coastguard Worker   // Prevent elision of the allocation.
68*61c4878aSAndroid Build Coastguard Worker   pw::test::DoNotOptimize(ptr);
69*61c4878aSAndroid Build Coastguard Worker   ASSERT_NE(ptr, nullptr);
70*61c4878aSAndroid Build Coastguard Worker   EXPECT_GE(system_metrics.allocated_bytes.value(), kSize);
71*61c4878aSAndroid Build Coastguard Worker 
72*61c4878aSAndroid Build Coastguard Worker   delete (ptr);
73*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(system_metrics.allocated_bytes.value(), 0U);
74*61c4878aSAndroid Build Coastguard Worker }
75*61c4878aSAndroid Build Coastguard Worker 
TEST_F(MallocTest,CallocFree)76*61c4878aSAndroid Build Coastguard Worker TEST_F(MallocTest, CallocFree) {
77*61c4878aSAndroid Build Coastguard Worker   constexpr size_t kNum = 4;
78*61c4878aSAndroid Build Coastguard Worker   constexpr size_t kSize = 64;
79*61c4878aSAndroid Build Coastguard Worker   auto& system_metrics = pw::malloc::GetSystemMetrics();
80*61c4878aSAndroid Build Coastguard Worker 
81*61c4878aSAndroid Build Coastguard Worker   void* ptr = calloc(kNum, kSize);
82*61c4878aSAndroid Build Coastguard Worker   ASSERT_NE(ptr, nullptr);
83*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(system_metrics.requested_bytes.value(), kNum * kSize);
84*61c4878aSAndroid Build Coastguard Worker 
85*61c4878aSAndroid Build Coastguard Worker   free(ptr);
86*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(system_metrics.allocated_bytes.value(), 0U);
87*61c4878aSAndroid Build Coastguard Worker }
88*61c4878aSAndroid Build Coastguard Worker 
TEST_F(MallocTest,ReallocFree)89*61c4878aSAndroid Build Coastguard Worker TEST_F(MallocTest, ReallocFree) {
90*61c4878aSAndroid Build Coastguard Worker   constexpr size_t kSize = 256;
91*61c4878aSAndroid Build Coastguard Worker   auto& system_metrics = pw::malloc::GetSystemMetrics();
92*61c4878aSAndroid Build Coastguard Worker 
93*61c4878aSAndroid Build Coastguard Worker   void* ptr = realloc(nullptr, kSize);
94*61c4878aSAndroid Build Coastguard Worker   ASSERT_NE(ptr, nullptr);
95*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(system_metrics.requested_bytes.value(), kSize);
96*61c4878aSAndroid Build Coastguard Worker 
97*61c4878aSAndroid Build Coastguard Worker   free(ptr);
98*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(system_metrics.allocated_bytes.value(), 0U);
99*61c4878aSAndroid Build Coastguard Worker }
100*61c4878aSAndroid Build Coastguard Worker 
TEST_F(MallocTest,MallocReallocFree)101*61c4878aSAndroid Build Coastguard Worker TEST_F(MallocTest, MallocReallocFree) {
102*61c4878aSAndroid Build Coastguard Worker   constexpr size_t kSize1 = 256;
103*61c4878aSAndroid Build Coastguard Worker   constexpr size_t kSize2 = 512;
104*61c4878aSAndroid Build Coastguard Worker   auto& system_metrics = pw::malloc::GetSystemMetrics();
105*61c4878aSAndroid Build Coastguard Worker 
106*61c4878aSAndroid Build Coastguard Worker   void* ptr = malloc(kSize1);
107*61c4878aSAndroid Build Coastguard Worker   ASSERT_NE(ptr, nullptr);
108*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(system_metrics.requested_bytes.value(), kSize1);
109*61c4878aSAndroid Build Coastguard Worker   std::memset(ptr, 1, kSize1);
110*61c4878aSAndroid Build Coastguard Worker 
111*61c4878aSAndroid Build Coastguard Worker   void* new_ptr = realloc(ptr, kSize2);
112*61c4878aSAndroid Build Coastguard Worker   ASSERT_NE(ptr, nullptr);
113*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(system_metrics.requested_bytes.value(), kSize2);
114*61c4878aSAndroid Build Coastguard Worker 
115*61c4878aSAndroid Build Coastguard Worker   // Using `new_ptr` prevents the call to `realloc from being optimized away.
116*61c4878aSAndroid Build Coastguard Worker   auto* bytes = std::launder(reinterpret_cast<uint8_t*>(new_ptr));
117*61c4878aSAndroid Build Coastguard Worker   for (size_t i = 0; i < kSize1; ++i) {
118*61c4878aSAndroid Build Coastguard Worker     EXPECT_EQ(bytes[i], 1U);
119*61c4878aSAndroid Build Coastguard Worker   }
120*61c4878aSAndroid Build Coastguard Worker 
121*61c4878aSAndroid Build Coastguard Worker   free(new_ptr);
122*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(system_metrics.allocated_bytes.value(), 0U);
123*61c4878aSAndroid Build Coastguard Worker }
124*61c4878aSAndroid Build Coastguard Worker 
125*61c4878aSAndroid Build Coastguard Worker // This test mimics pw_tokenizer//detokenize_test.cc in order to perform memory
126*61c4878aSAndroid Build Coastguard Worker // allocations as a result of manipulating a std::unordered_map.
127*61c4878aSAndroid Build Coastguard Worker // See also b/345526413 for the failure that motivated this test.
TEST_F(MallocTest,Detokenize)128*61c4878aSAndroid Build Coastguard Worker TEST_F(MallocTest, Detokenize) {
129*61c4878aSAndroid Build Coastguard Worker   static constexpr char kTestDatabase[] =
130*61c4878aSAndroid Build Coastguard Worker       "TOKENS\0\0"
131*61c4878aSAndroid Build Coastguard Worker       "\x06\x00\x00\x00"  // Number of tokens in this database.
132*61c4878aSAndroid Build Coastguard Worker       "\0\0\0\0"
133*61c4878aSAndroid Build Coastguard Worker       "\x01\x00\x00\x00----"
134*61c4878aSAndroid Build Coastguard Worker       "\x05\x00\x00\x00----"
135*61c4878aSAndroid Build Coastguard Worker       "\xFF\x00\x00\x00----"
136*61c4878aSAndroid Build Coastguard Worker       "\xFF\xEE\xEE\xDD----"
137*61c4878aSAndroid Build Coastguard Worker       "\xEE\xEE\xEE\xEE----"
138*61c4878aSAndroid Build Coastguard Worker       "\x9D\xA7\x97\xF8----"
139*61c4878aSAndroid Build Coastguard Worker       "One\0"
140*61c4878aSAndroid Build Coastguard Worker       "TWO\0"
141*61c4878aSAndroid Build Coastguard Worker       "333\0"
142*61c4878aSAndroid Build Coastguard Worker       "FOUR\0"
143*61c4878aSAndroid Build Coastguard Worker       "$AQAAAA==\0"
144*61c4878aSAndroid Build Coastguard Worker       "■msg♦This is $AQAAAA== message■module♦■file♦file.txt";
145*61c4878aSAndroid Build Coastguard Worker   pw::tokenizer::Detokenizer detok(
146*61c4878aSAndroid Build Coastguard Worker       pw::tokenizer::TokenDatabase::Create<kTestDatabase>());
147*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(detok.Detokenize("\1\0\0\0"sv).BestString(), "One");
148*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(detok.Detokenize("\5\0\0\0"sv).BestString(), "TWO");
149*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(detok.Detokenize("\xff\x00\x00\x00"sv).BestString(), "333");
150*61c4878aSAndroid Build Coastguard Worker   EXPECT_EQ(detok.Detokenize("\xff\xee\xee\xdd"sv).BestString(), "FOUR");
151*61c4878aSAndroid Build Coastguard Worker }
152*61c4878aSAndroid Build Coastguard Worker 
153*61c4878aSAndroid Build Coastguard Worker }  // namespace
154