| // 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 |