Line data Source code
1 : /* 2 : * 3 : * Copyright (c) 2020-2021 Project CHIP Authors 4 : * All rights reserved. 5 : * 6 : * Licensed under the Apache License, Version 2.0 (the "License"); 7 : * you may not use this file except in compliance with the License. 8 : * You may obtain a copy of the License at 9 : * 10 : * http://www.apache.org/licenses/LICENSE-2.0 11 : * 12 : * Unless required by applicable law or agreed to in writing, software 13 : * distributed under the License is distributed on an "AS IS" BASIS, 14 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 : * See the License for the specific language governing permissions and 16 : * limitations under the License. 17 : */ 18 : 19 : /** 20 : * @file 21 : * This file defines heap memory allocation APIs for CHIP. 22 : * 23 : */ 24 : 25 : #pragma once 26 : 27 : #include <lib/core/CHIPError.h> 28 : #include <stdlib.h> 29 : 30 : #include <memory> 31 : #include <new> 32 : #include <utility> 33 : 34 : namespace chip { 35 : namespace Platform { 36 : 37 : #define CHIP_ZERO_AT(value) \ 38 : do \ 39 : { \ 40 : memset(&value, 0, sizeof(value)); \ 41 : } while (0) 42 : 43 : /** 44 : * This function is called by CHIP layer to initialize memory and resources 45 : * required for proper functionality of the CHIP memory allocator. 46 : * This function is platform specific and might be empty in certain cases. 47 : * For example, this function is doing nothing when the C Standard Library malloc() 48 : * and free() functions are used for memory allocation. 49 : * 50 : * @param[in] buf A pointer to a dedicated memory buffer, which should be used as 51 : * a memory pool for CHIP memory allocation. 52 : * This input is optional (defaults to NULL) and shouldn't be used 53 : * if a dedicated memory buffer is not used. 54 : * 55 : * @param[in] bufSize Size of a dedicated memory buffer. This input is optional (defaults to 0) 56 : * and shouldn't be used if dedicated memory buffer is not used. 57 : * When a dedicated memory buffer is used the function checks and 58 : * generates an error if buffer size is not big enough to support 59 : * CHIP use cases. 60 : * 61 : * @retval #CHIP_ERROR_BUFFER_TOO_SMALL If dedicated input buffer size is not sufficient 62 : * to support CHIP use cases. 63 : * @retval #CHIP_NO_ERROR On success. 64 : * @retval other An error generated by platform-specific memory 65 : * initialization function. 66 : * 67 : */ 68 : extern CHIP_ERROR MemoryInit(void * buf = nullptr, size_t bufSize = 0); 69 : 70 : /** 71 : * This function is called by the CHIP layer to releases all resources that were allocated 72 : * by MemoryInit() function. 73 : * This function can be an empty call if there is no need to release resources. For example, 74 : * this is the case when the C Standard Library malloc() and free() functions are used 75 : * for memory allocation. 76 : * 77 : */ 78 : extern void MemoryShutdown(); 79 : 80 : /** 81 : * This function is called by the CHIP layer to allocate a block of memory of "size" bytes. 82 : * 83 : * @param[in] size Specifies requested memory size in bytes. 84 : * 85 : * @retval Pointer to a memory block in case of success. 86 : * @retval NULL-pointer if memory allocation fails. 87 : * 88 : */ 89 : extern void * MemoryAlloc(size_t size); 90 : 91 : /** 92 : * This function is called by the CHIP layer to allocate a block of memory for an array of num 93 : * elements, each of them size bytes long, and initializes all its bits to zero. 94 : * The effective result is the allocation of a zero-initialized memory block of (num*size) bytes. 95 : * 96 : * @param[in] num Specifies number of elements to allocate. 97 : * @param[in] size Specifies size of each element in bytes. 98 : * 99 : * @retval Pointer to a memory block in case of success. 100 : * @retval NULL-pointer if memory allocation fails. 101 : * 102 : */ 103 : extern void * MemoryCalloc(size_t num, size_t size); 104 : 105 : /** 106 : * This function is called by the Chip layer to change the size of the memory block pointed to by p. 107 : * The function may move the memory block to a new location (whose address is returned by the function). 108 : * The content of the memory block is preserved up to the lesser of the new and old sizes, even if the 109 : * block is moved to a new location. If the new size is larger, the value of the newly allocated portion 110 : * is indeterminate. 111 : 112 : * In case that p is a null pointer, the function behaves like malloc, assigning a new block of size bytes 113 : * and returning a pointer to its beginning. 114 : * 115 : * @param[in] p Pointer to a memory block previously allocated with MemoryAlloc, MemoryCalloc 116 : * or MemoryRealloc. 117 : * @param[in] size Specifies new size for the memory block, in bytes.. 118 : * 119 : * @retval Pointer to a memory block in case of success. 120 : * @retval NULL-pointer if memory allocation fails. 121 : * 122 : */ 123 : extern void * MemoryRealloc(void * p, size_t size); 124 : 125 : /** 126 : * This function is called by the Chip layer to release a memory block allocated by 127 : * the MemoryAlloc(), MemoryCalloc or MemoryRealloc. 128 : * @param[in] p Pointer to a memory block that should be released. 129 : * 130 : */ 131 : extern void MemoryFree(void * p); 132 : 133 : /** 134 : * This function wraps the operator `new` with placement-new using MemoryAlloc(). 135 : * Instead of 136 : * p = new T(arguments) 137 : * use 138 : * p = New<T>(arguments) 139 : * In a few cases it may be necessary to add explicit casts to arguments, notably 140 : * when passing integer constants to smaller integer parameters. 141 : */ 142 : template <typename T, typename... Args> 143 5966749 : inline T * New(Args &&... args) 144 : { 145 5966749 : void * p = MemoryAlloc(sizeof(T)); 146 5966749 : if (p != nullptr) 147 : { 148 5966749 : return new (p) T(std::forward<Args>(args)...); 149 : } 150 0 : return nullptr; 151 : } 152 : 153 : /** 154 : * This function wraps the operator `delete` with using MemoryFree(). 155 : * Instead of 156 : * delete p 157 : * use 158 : * Delete(p) 159 : */ 160 : template <typename T> 161 5665348 : inline void Delete(T * p) 162 : { 163 5665348 : if (p == nullptr) 164 : { 165 0 : return; 166 : } 167 : 168 5665348 : p->~T(); 169 5665348 : MemoryFree(p); 170 : } 171 : 172 : template <typename T> 173 : struct Deleter 174 : { 175 390 : void operator()(T * p) { Delete(p); } 176 : }; 177 : 178 : template <typename T> 179 : using UniquePtr = std::unique_ptr<T, Deleter<T>>; 180 : 181 : template <typename T, typename... Args> 182 4 : inline UniquePtr<T> MakeUnique(Args &&... args) 183 : { 184 4 : return UniquePtr<T>(New<T>(std::forward<Args>(args)...)); 185 : } 186 : 187 : template <typename T> 188 : using SharedPtr = std::shared_ptr<T>; 189 : 190 : template <typename T, typename... Args> 191 14 : inline SharedPtr<T> MakeShared(Args &&... args) 192 : { 193 14 : return SharedPtr<T>(New<T>(std::forward<Args>(args)...), Deleter<T>()); 194 : } 195 : 196 : template <typename T> 197 : using WeakPtr = std::weak_ptr<T>; 198 : 199 : // See MemoryDebugCheckPointer(). 200 : extern bool MemoryInternalCheckPointer(const void * p, size_t min_size); 201 : 202 : /** 203 : * In debug builds, test the validity of a pointer obtained from a chip::Platform memory allocation. 204 : * 205 : * @param[in] p Pointer to a memory block previously allocated with MemoryAlloc, MemoryCalloc, 206 : * MemoryRealloc, or New, and not freed. 207 : * @param[in] min_size Gives a size that the allocated block is expected to be able to hold. 208 : * 209 : * @e Unless configured with #CHIP_CONFIG_MEMORY_DEBUG_CHECKS, this function returns `true` without performing 210 : * any check, inlined with the expectation that the compiler can remove any associated failure code. 211 : * 212 : * With #CHIP_CONFIG_MEMORY_DEBUG_CHECKS enabled: 213 : * 214 : * This function is guaranteed to return `false` if \a p is `nullptr`. The function returns `true` if \a p is a valid 215 : * pointer to an allocation *and* the implementation memory manager is in a fully functioning state. 216 : * 217 : * @note For non-null \a p, the function *may* return `true` even if the pointer is invalid. That is, a particular 218 : * implementation or configuration is not guaranteed to catch any particular faulty state. 219 : * @note For non-null \a p, the function return value *may* be incorrect if the memory manager is in a faulty state 220 : * (e.g. corrupt heap), even if the faulty state does not directly involve \a p. 221 : * @note For non-null \a p, the function *may* abort the program rather than return at all if the memory manager is in 222 : * a faulty state, even if \a p is valid. 223 : * @note For a non-null \a p, checking *may* be slow. 224 : * 225 : * 226 : * @return An implementation- and configuration-defined estimate of whether \a p is a valid allocated pointer. 227 : */ 228 8691617 : inline bool MemoryDebugCheckPointer(const void * p, size_t min_size = 0) 229 : { 230 : #if CHIP_CONFIG_MEMORY_DEBUG_CHECKS 231 : return MemoryInternalCheckPointer(p, min_size); 232 : #else // CHIP_CONFIG_MEMORY_DEBUG_CHECKS 233 8691617 : return true; 234 : #endif // CHIP_CONFIG_MEMORY_DEBUG_CHECKS 235 : } 236 : 237 : } // namespace Platform 238 : } // namespace chip