|  | // Copyright Microsoft and CHERIoT Contributors. | 
|  | // SPDX-License-Identifier: MIT | 
|  |  | 
|  | #pragma once | 
|  | /** | 
|  | * This file contains concrete implementations of the C++ replaceable new and | 
|  | * delete functions, as thin wrappers around calls to the allocator | 
|  | * compartment. | 
|  | * | 
|  | * These are intended to be small and inlined for normal use but have blocking | 
|  | * behaviour that may be inappropriate for some uses.  Individual compartments | 
|  | * can opt out of these definitions by defining `CHERIOT_NO_NEW_DELETE`. | 
|  | * | 
|  | * The `CHERIOT_NO_AMBIENT_MALLOC` macro will also hide these, because they | 
|  | * depend on having ambient authority to allocate memory. | 
|  | */ | 
|  | #include_next <new> | 
|  | #include <stdlib.h> | 
|  |  | 
|  | #if !defined(CHERIOT_NO_NEW_DELETE) && !defined(CHERIOT_NO_AMBIENT_MALLOC) | 
|  | namespace std | 
|  | { | 
|  | /** | 
|  | * Implementation details. | 
|  | */ | 
|  | namespace __new_detail | 
|  | { | 
|  | /** | 
|  | * Class for managing the handler for new and delete. | 
|  | */ | 
|  | class NewHelper | 
|  | { | 
|  | /** | 
|  | * Pointer to the handler for allocation failures. | 
|  | */ | 
|  | static inline std::new_handler newHandler; | 
|  |  | 
|  | /// The standard getter is allowed to access the new handler | 
|  | friend std::new_handler std::get_new_handler() _NOEXCEPT; | 
|  | /// The standard setter is allowed to modify the new handler | 
|  | friend std::new_handler std::set_new_handler(new_handler) _NOEXCEPT; | 
|  |  | 
|  | public: | 
|  | /** | 
|  | * Helper to call the allocator and raise an error if allocation fails. | 
|  | */ | 
|  | static inline void *allocate(size_t size) | 
|  | { | 
|  | void *ptr = malloc(size); | 
|  | while (ptr == nullptr) | 
|  | { | 
|  | if (newHandler) | 
|  | { | 
|  | newHandler(); | 
|  | } | 
|  | else | 
|  | { | 
|  | break; | 
|  | } | 
|  | } | 
|  | return ptr; | 
|  | } | 
|  | }; | 
|  | } // namespace __new_detail | 
|  |  | 
|  | /** | 
|  | * Return the handler for allocation failure. | 
|  | */ | 
|  | inline new_handler get_new_handler() noexcept | 
|  | { | 
|  | return __new_detail::NewHelper::newHandler; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * Set the handler for allocation failure and return the old one. | 
|  | * | 
|  | * Note: This implementation is *not* thread safe! | 
|  | */ | 
|  | inline new_handler set_new_handler(new_handler new_p) noexcept | 
|  | { | 
|  | auto old = __new_detail::NewHelper::newHandler; | 
|  | __new_detail::NewHelper::newHandler = new_p; | 
|  | return old; | 
|  | } | 
|  |  | 
|  | } // namespace std | 
|  |  | 
|  | #	pragma clang diagnostic push | 
|  | #	pragma clang diagnostic ignored "-Winline-new-delete" | 
|  |  | 
|  | _LIBCPP_NODISCARD_AFTER_CXX17 | 
|  | __always_inline _LIBCPP_OVERRIDABLE_FUNC_VIS inline void * | 
|  | operator new(std::size_t size) | 
|  | { | 
|  | return std::__new_detail::NewHelper::allocate(size); | 
|  | } | 
|  |  | 
|  | _LIBCPP_NODISCARD_AFTER_CXX17 | 
|  | __always_inline _LIBCPP_OVERRIDABLE_FUNC_VIS inline void * | 
|  | operator new(std::size_t size, const std::nothrow_t &) noexcept | 
|  | { | 
|  | return std::__new_detail::NewHelper::allocate(size); | 
|  | } | 
|  |  | 
|  | _LIBCPP_NODISCARD_AFTER_CXX17 | 
|  | __always_inline _LIBCPP_OVERRIDABLE_FUNC_VIS inline void * | 
|  | operator new[](std::size_t size) | 
|  | { | 
|  | return std::__new_detail::NewHelper::allocate(size); | 
|  | } | 
|  | _LIBCPP_NODISCARD_AFTER_CXX17 | 
|  | __always_inline _LIBCPP_OVERRIDABLE_FUNC_VIS inline void * | 
|  | operator new[](std::size_t size, const std::nothrow_t &) noexcept | 
|  | { | 
|  | return std::__new_detail::NewHelper::allocate(size); | 
|  | } | 
|  | __always_inline _LIBCPP_OVERRIDABLE_FUNC_VIS inline void | 
|  | operator delete(void *ptr) noexcept | 
|  | { | 
|  | ::free(ptr); | 
|  | } | 
|  | __always_inline _LIBCPP_OVERRIDABLE_FUNC_VIS inline void | 
|  | operator delete(void *ptr, std::size_t size) noexcept | 
|  | { | 
|  | ::free(ptr); | 
|  | } | 
|  |  | 
|  | __always_inline _LIBCPP_OVERRIDABLE_FUNC_VIS inline void | 
|  | operator delete[](void *ptr) noexcept | 
|  | { | 
|  | ::free(ptr); | 
|  | } | 
|  | __always_inline _LIBCPP_OVERRIDABLE_FUNC_VIS inline void | 
|  | operator delete[](void *ptr, std::size_t size) noexcept | 
|  | { | 
|  | ::free(ptr); | 
|  | } | 
|  | __always_inline _LIBCPP_OVERRIDABLE_FUNC_VIS inline void | 
|  | operator delete[](void *ptr, const std::nothrow_t &) noexcept | 
|  | { | 
|  | ::free(ptr); | 
|  | } | 
|  |  | 
|  | #	if 0 | 
|  | // Until the allocator exposes a memalign interface, we don't support aligned allocation. | 
|  | [[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment); | 
|  | [[nodiscard]] void* operator new(std::size_t size, std::align_val_t alignment, | 
|  | const std::nothrow_t&) noexcept; | 
|  |  | 
|  | void operator delete(void *ptr, std::align_val_t alignment) noexcept; | 
|  | void operator delete(void            *ptr, | 
|  | std::size_t      size, | 
|  | std::align_val_t alignment) noexcept; | 
|  | void operator delete(void *ptr, const std::nothrow_t &) noexcept; | 
|  | void operator delete(void            *ptr, | 
|  | std::align_val_t alignment, | 
|  | const std::nothrow_t &) noexcept; | 
|  | [[nodiscard]] void *operator new[](std::size_t      size, | 
|  | std::align_val_t alignment); | 
|  | [[nodiscard]] void *operator new[](std::size_t      size, | 
|  | std::align_val_t alignment, | 
|  | const std::nothrow_t &) noexcept; | 
|  | void operator delete[](void *ptr, std::align_val_t alignment) noexcept; | 
|  | void operator delete[](void            *ptr, | 
|  | std::size_t      size, | 
|  | std::align_val_t alignment) noexcept; | 
|  | void operator delete[](void            *ptr, | 
|  | std::align_val_t alignment, | 
|  | const std::nothrow_t &) noexcept; | 
|  |  | 
|  | #	endif | 
|  | #	pragma clang diagnostic pop | 
|  | #endif |