/* * * Copyright (c) 2020-2021 Project CHIP Authors * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @file * This file defines heap memory allocation APIs for CHIP. * */ #pragma once #include #include #include #include #include namespace chip { namespace Platform { #define CHIP_ZERO_AT(value) \ do \ { \ memset(&value, 0, sizeof(value)); \ } while (0) /** * This function is called by CHIP layer to initialize memory and resources * required for proper functionality of the CHIP memory allocator. * This function is platform specific and might be empty in certain cases. * For example, this function is doing nothing when the C Standard Library malloc() * and free() functions are used for memory allocation. * * @param[in] buf A pointer to a dedicated memory buffer, which should be used as * a memory pool for CHIP memory allocation. * This input is optional (defaults to NULL) and shouldn't be used * if a dedicated memory buffer is not used. * * @param[in] bufSize Size of a dedicated memory buffer. This input is optional (defaults to 0) * and shouldn't be used if dedicated memory buffer is not used. * When a dedicated memory buffer is used the function checks and * generates an error if buffer size is not big enough to support * CHIP use cases. * * @retval #CHIP_ERROR_BUFFER_TOO_SMALL If dedicated input buffer size is not sufficient * to support CHIP use cases. * @retval #CHIP_NO_ERROR On success. * @retval other An error generated by platform-specific memory * initialization function. * */ extern CHIP_ERROR MemoryInit(void * buf = nullptr, size_t bufSize = 0); /** * This function is called by the CHIP layer to releases all resources that were allocated * by MemoryInit() function. * This function can be an empty call if there is no need to release resources. For example, * this is the case when the C Standard Library malloc() and free() functions are used * for memory allocation. * */ extern void MemoryShutdown(); /** * This function is called by the CHIP layer to allocate a block of memory of "size" bytes. * * @param[in] size Specifies requested memory size in bytes. * * @retval Pointer to a memory block in case of success. * @retval NULL-pointer if memory allocation fails. * */ extern void * MemoryAlloc(size_t size); /** * This function is called by the CHIP layer to allocate a block of memory for an array of num * elements, each of them size bytes long, and initializes all its bits to zero. * The effective result is the allocation of a zero-initialized memory block of (num*size) bytes. * * @param[in] num Specifies number of elements to allocate. * @param[in] size Specifies size of each element in bytes. * * @retval Pointer to a memory block in case of success. * @retval NULL-pointer if memory allocation fails. * */ extern void * MemoryCalloc(size_t num, size_t size); /** * This function is called by the Chip layer to change the size of the memory block pointed to by p. * The function may move the memory block to a new location (whose address is returned by the function). * The content of the memory block is preserved up to the lesser of the new and old sizes, even if the * block is moved to a new location. If the new size is larger, the value of the newly allocated portion * is indeterminate. * In case that p is a null pointer, the function behaves like malloc, assigning a new block of size bytes * and returning a pointer to its beginning. * * @param[in] p Pointer to a memory block previously allocated with MemoryAlloc, MemoryCalloc * or MemoryRealloc. * @param[in] size Specifies new size for the memory block, in bytes.. * * @retval Pointer to a memory block in case of success. * @retval NULL-pointer if memory allocation fails. * */ extern void * MemoryRealloc(void * p, size_t size); /** * This function is called by the Chip layer to release a memory block allocated by * the MemoryAlloc(), MemoryCalloc or MemoryRealloc. * @param[in] p Pointer to a memory block that should be released. * */ extern void MemoryFree(void * p); /** * This function wraps the operator `new` with placement-new using MemoryAlloc(). * Instead of * p = new T(arguments) * use * p = New(arguments) * In a few cases it may be necessary to add explicit casts to arguments, notably * when passing integer constants to smaller integer parameters. */ template inline T * New(Args &&... args) { void * p = MemoryAlloc(sizeof(T)); if (p != nullptr) { return new (p) T(std::forward(args)...); } return nullptr; } /** * This function wraps the operator `delete` with using MemoryFree(). * Instead of * delete p * use * Delete(p) */ template inline void Delete(T * p) { if (p == nullptr) { return; } p->~T(); MemoryFree(p); } template struct Deleter { void operator()(T * p) { Delete(p); } }; template using UniquePtr = std::unique_ptr>; template inline UniquePtr MakeUnique(Args &&... args) { return UniquePtr(New(std::forward(args)...)); } template using SharedPtr = std::shared_ptr; template inline SharedPtr MakeShared(Args &&... args) { return SharedPtr(New(std::forward(args)...), Deleter()); } template using WeakPtr = std::weak_ptr; // See MemoryDebugCheckPointer(). extern bool MemoryInternalCheckPointer(const void * p, size_t min_size); /** * In debug builds, test the validity of a pointer obtained from a chip::Platform memory allocation. * * @param[in] p Pointer to a memory block previously allocated with MemoryAlloc, MemoryCalloc, * MemoryRealloc, or New, and not freed. * @param[in] min_size Gives a size that the allocated block is expected to be able to hold. * * @e Unless configured with #CHIP_CONFIG_MEMORY_DEBUG_CHECKS, this function returns `true` without performing * any check, inlined with the expectation that the compiler can remove any associated failure code. * * With #CHIP_CONFIG_MEMORY_DEBUG_CHECKS enabled: * * This function is guaranteed to return `false` if \a p is `nullptr`. The function returns `true` if \a p is a valid * pointer to an allocation *and* the implementation memory manager is in a fully functioning state. * * @note For non-null \a p, the function *may* return `true` even if the pointer is invalid. That is, a particular * implementation or configuration is not guaranteed to catch any particular faulty state. * @note For non-null \a p, the function return value *may* be incorrect if the memory manager is in a faulty state * (e.g. corrupt heap), even if the faulty state does not directly involve \a p. * @note For non-null \a p, the function *may* abort the program rather than return at all if the memory manager is in * a faulty state, even if \a p is valid. * @note For a non-null \a p, checking *may* be slow. * * * @return An implementation- and configuration-defined estimate of whether \a p is a valid allocated pointer. */ inline bool MemoryDebugCheckPointer(const void * p, size_t min_size = 0) { #if CHIP_CONFIG_MEMORY_DEBUG_CHECKS return MemoryInternalCheckPointer(p, min_size); #else // CHIP_CONFIG_MEMORY_DEBUG_CHECKS return true; #endif // CHIP_CONFIG_MEMORY_DEBUG_CHECKS } } // namespace Platform } // namespace chip