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