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_allocator/buddy_allocator.h"
16
17 #include <array>
18 #include <cstddef>
19
20 #include "pw_allocator/fuzzing.h"
21 #include "pw_unit_test/framework.h"
22
23 namespace {
24
25 // Test fixtures.
26
27 using BuddyAllocator = ::pw::allocator::BuddyAllocator<>;
28 using ::pw::allocator::Layout;
29
30 static constexpr size_t kBufferSize = 0x400;
31
32 // Unit tests.
33
TEST(BuddyAllocatorTest,ExplicitlyInit)34 TEST(BuddyAllocatorTest, ExplicitlyInit) {
35 std::array<std::byte, kBufferSize> buffer;
36 BuddyAllocator allocator;
37 allocator.Init(buffer);
38 }
39
TEST(BuddyAllocatorTest,AllocateSmall)40 TEST(BuddyAllocatorTest, AllocateSmall) {
41 std::array<std::byte, kBufferSize> buffer;
42 BuddyAllocator allocator(buffer);
43 void* ptr = allocator.Allocate(Layout(BuddyAllocator::kMinOuterSize / 2, 1));
44 ASSERT_NE(ptr, nullptr);
45 allocator.Deallocate(ptr);
46 }
47
TEST(BuddyAllocatorTest,AllocateAllBlocks)48 TEST(BuddyAllocatorTest, AllocateAllBlocks) {
49 std::array<std::byte, kBufferSize> buffer;
50 BuddyAllocator allocator(buffer);
51 pw::Vector<void*, kBufferSize / BuddyAllocator::kMinOuterSize> ptrs;
52 while (true) {
53 void* ptr = allocator.Allocate(Layout(1, 1));
54 if (ptr == nullptr) {
55 break;
56 }
57 ptrs.push_back(ptr);
58 }
59 while (!ptrs.empty()) {
60 allocator.Deallocate(ptrs.back());
61 ptrs.pop_back();
62 }
63 }
64
TEST(BuddyAllocatorTest,AllocateLarge)65 TEST(BuddyAllocatorTest, AllocateLarge) {
66 std::array<std::byte, kBufferSize> buffer;
67 BuddyAllocator allocator(buffer);
68 void* ptr = allocator.Allocate(Layout(48, 1));
69 ASSERT_NE(ptr, nullptr);
70 allocator.Deallocate(ptr);
71 }
72
TEST(BuddyAllocatorTest,AllocateExcessiveSize)73 TEST(BuddyAllocatorTest, AllocateExcessiveSize) {
74 std::array<std::byte, kBufferSize> buffer;
75 BuddyAllocator allocator(buffer);
76 void* ptr = allocator.Allocate(Layout(786, 1));
77 EXPECT_EQ(ptr, nullptr);
78 }
79
TEST(BuddyAllocatorTest,AllocateExcessiveAlignment)80 TEST(BuddyAllocatorTest, AllocateExcessiveAlignment) {
81 std::array<std::byte, kBufferSize> buffer;
82 BuddyAllocator allocator(buffer);
83 void* ptr = allocator.Allocate(Layout(48, 32));
84 EXPECT_EQ(ptr, nullptr);
85 }
86
87 // Fuzz tests.
88
89 using ::pw::allocator::test::DefaultArbitraryRequests;
90 using ::pw::allocator::test::Request;
91 using ::pw::allocator::test::TestHarness;
92
NeverCrashes(const pw::Vector<Request> & requests)93 void NeverCrashes(const pw::Vector<Request>& requests) {
94 static std::array<std::byte, kBufferSize> buffer;
95 static BuddyAllocator allocator(buffer);
96 static TestHarness fuzzer(allocator);
97 fuzzer.HandleRequests(requests);
98 }
99
100 FUZZ_TEST(BucketBlockAllocatorFuzzTest, NeverCrashes)
101 .WithDomains(DefaultArbitraryRequests());
102
103 } // namespace
104