xref: /aosp_15_r20/external/pigweed/pw_malloc/malloc.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 <cstring>
18 #include <new>
19 
20 #include "pw_allocator/allocator.h"
21 #include "pw_allocator/metrics.h"
22 #include "pw_allocator/synchronized_allocator.h"
23 #include "pw_allocator/tracking_allocator.h"
24 #include "pw_assert/check.h"
25 #include "pw_malloc/config.h"
26 #include "pw_metric/metric.h"
27 #include "pw_tokenizer/tokenize.h"
28 
29 namespace {
30 
31 using ::pw::allocator::Layout;
32 using ::pw::allocator::NoMetrics;
33 using ::pw::allocator::NoSync;
34 using ::pw::allocator::SynchronizedAllocator;
35 using ::pw::allocator::TrackingAllocator;
36 using ::pw::metric::Token;
37 
38 const PW_MALLOC_METRICS_TYPE* system_metrics = nullptr;
39 
40 /// Instantiates the system allocator, based on the module configuration.
41 ///
42 /// This function must be a template to conditionally omit constexpr branches.
43 template <typename MetricsType, typename LockType>
WrapSystemAllocator()44 pw::Allocator& WrapSystemAllocator() {
45   pw::Allocator* system = pw::malloc::GetSystemAllocator();
46   if constexpr (!std::is_same_v<MetricsType, NoMetrics>) {
47     constexpr static Token kToken = PW_TOKENIZE_STRING("system allocator");
48     static TrackingAllocator<MetricsType> tracker(kToken, *system);
49     system = &tracker;
50     system_metrics = &tracker.metrics();
51   } else {
52     static MetricsType no_metrics;
53     system_metrics = &no_metrics;
54   }
55   if constexpr (!std::is_same_v<LockType, NoSync>) {
56     static SynchronizedAllocator<LockType> synchronized(*system);
57     system = &synchronized;
58   }
59   return *system;
60 }
61 
SystemAllocator()62 pw::Allocator& SystemAllocator() {
63   static pw::Allocator& system =
64       WrapSystemAllocator<PW_MALLOC_METRICS_TYPE, PW_MALLOC_LOCK_TYPE>();
65   return system;
66 }
67 
68 }  // namespace
69 
70 namespace pw::malloc {
71 
InitSystemAllocator(void * heap_low_addr,void * heap_high_addr)72 void InitSystemAllocator(void* heap_low_addr, void* heap_high_addr) {
73   auto* lo = std::launder(reinterpret_cast<std::byte*>(heap_low_addr));
74   auto* hi = std::launder(reinterpret_cast<std::byte*>(heap_high_addr));
75   InitSystemAllocator(pw::ByteSpan(lo, (hi - lo)));
76 }
77 
GetSystemMetrics()78 const PW_MALLOC_METRICS_TYPE& GetSystemMetrics() {
79   SystemAllocator();
80   return *system_metrics;
81 }
82 
83 }  // namespace pw::malloc
84 
85 PW_EXTERN_C_START
86 
pw_MallocInit(uint8_t * heap_low_addr,uint8_t * heap_high_addr)87 void pw_MallocInit(uint8_t* heap_low_addr, uint8_t* heap_high_addr) {
88   pw::malloc::InitSystemAllocator(heap_low_addr, heap_high_addr);
89 }
90 
91 // Wrapper functions for malloc, free, realloc and calloc.
92 // With linker options "-Wl --wrap=<function name>", linker will link
93 // "__wrap_<function name>" with "<function_name>", and calling
94 // "<function name>" will call "__wrap_<function name>" instead
__wrap_malloc(size_t size)95 void* __wrap_malloc(size_t size) {
96   return SystemAllocator().Allocate(Layout(size));
97 }
98 
__wrap_free(void * ptr)99 void __wrap_free(void* ptr) { SystemAllocator().Deallocate(ptr); }
100 
__wrap_realloc(void * ptr,size_t size)101 void* __wrap_realloc(void* ptr, size_t size) {
102   return SystemAllocator().Reallocate(ptr, Layout(size));
103 }
104 
__wrap_calloc(size_t num,size_t size)105 void* __wrap_calloc(size_t num, size_t size) {
106   if (PW_MUL_OVERFLOW(num, size, &size)) {
107     return nullptr;
108   }
109   void* ptr = __wrap_malloc(size);
110   if (ptr != nullptr) {
111     std::memset(ptr, 0, size);
112   }
113   return ptr;
114 }
115 
__wrap__malloc_r(struct _reent *,size_t size)116 void* __wrap__malloc_r(struct _reent*, size_t size) {
117   return __wrap_malloc(size);
118 }
119 
__wrap__free_r(struct _reent *,void * ptr)120 void __wrap__free_r(struct _reent*, void* ptr) { __wrap_free(ptr); }
121 
__wrap__realloc_r(struct _reent *,void * ptr,size_t size)122 void* __wrap__realloc_r(struct _reent*, void* ptr, size_t size) {
123   return __wrap_realloc(ptr, size);
124 }
125 
__wrap__calloc_r(struct _reent *,size_t num,size_t size)126 void* __wrap__calloc_r(struct _reent*, size_t num, size_t size) {
127   return __wrap_calloc(num, size);
128 }
129 
130 PW_EXTERN_C_END
131