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