From fb0c97b22006be632b29e28a0e6a8627d0e47987 Mon Sep 17 00:00:00 2001 From: delphi Date: Thu, 14 Oct 2021 15:20:07 +0300 Subject: [PATCH 1/2] Make operators `new` and `delete` weak symbols by default Signed-off-by: delphi --- ext/gcc/new_delete.cpp.in | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ext/gcc/new_delete.cpp.in b/ext/gcc/new_delete.cpp.in index 920aaa1142..a198a9f813 100644 --- a/ext/gcc/new_delete.cpp.in +++ b/ext/gcc/new_delete.cpp.in @@ -78,26 +78,40 @@ new_assert(size_t size) } // ---------------------------------------------------------------------------- +modm_weak void* operator new (std::size_t size) { return new_assert(size); } +modm_weak void* operator new[](std::size_t size) { return new_assert(size); } +modm_weak void* operator new (std::size_t size, const std::nothrow_t&) noexcept { return malloc(size); } +modm_weak void* operator new[](std::size_t size, const std::nothrow_t&) noexcept { return malloc(size); } %% if with_memory_traits +modm_weak void* operator new (std::size_t size, modm::MemoryTraits traits) { return new_assert(size, traits); } +modm_weak void* operator new[](std::size_t size, modm::MemoryTraits traits) { return new_assert(size, traits); } +modm_weak void* operator new (std::size_t size, modm::MemoryTraits traits, const std::nothrow_t&) noexcept { return malloc_traits(size, traits.value); } +modm_weak void* operator new[](std::size_t size, modm::MemoryTraits traits, const std::nothrow_t&) noexcept { return malloc_traits(size, traits.value); } %% endif // ---------------------------------------------------------------------------- +modm_weak void operator delete (void *ptr) noexcept { free(ptr); } +modm_weak void operator delete[](void* ptr) noexcept { free(ptr); } +modm_weak void operator delete (void* ptr, std::size_t) noexcept { free(ptr); } +modm_weak void operator delete[](void* ptr, std::size_t) noexcept { free(ptr); } +modm_weak void operator delete (void* ptr, const std::nothrow_t&) noexcept { free(ptr); } +modm_weak void operator delete[](void* ptr, const std::nothrow_t&) noexcept { free(ptr); } From 387a625ba5377d6e4f52ffa5fddb360abbb29e9f Mon Sep 17 00:00:00 2001 From: Niklas Hauser Date: Thu, 14 Oct 2021 19:23:39 +0200 Subject: [PATCH 2/2] [heap] Use empty default implementation for delete --- .../nucleo_g071rb/custom_allocator/main.cpp | 14 ++++++++--- ext/gcc/module_c++.lb | 3 ++- ext/gcc/new_delete.cpp.in | 23 ++++++++++++++----- src/modm/platform/heap/cortex/module.md | 16 +++++++++++++ 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/examples/nucleo_g071rb/custom_allocator/main.cpp b/examples/nucleo_g071rb/custom_allocator/main.cpp index b5f94025ac..c53f990ab1 100644 --- a/examples/nucleo_g071rb/custom_allocator/main.cpp +++ b/examples/nucleo_g071rb/custom_allocator/main.cpp @@ -34,6 +34,10 @@ extern "C" void* _sbrk_r(struct _reent *, ptrdiff_t size) } return (void*) heap; } +extern "C" void operator_delete(void* ptr) +{ + free(ptr); +} // ---------------------------------------------------------------------------- int main() @@ -47,7 +51,7 @@ int main() traits.value, start, end, size); } - void* ptr; + uint8_t* ptr; size_t counter{0}; while (true) { @@ -55,9 +59,13 @@ int main() modm::delay(200ms); // leak memory until heap is exhausted - ptr = malloc(1024); - if (ptr) counter++; + ptr = new uint8_t[1024]; + if (ptr) { + ptr[0] = counter; + counter++; + } MODM_LOG_INFO << "Allocated " << counter << "kb of heap!" << modm::endl; + // delete ptr; } return 0; diff --git a/ext/gcc/module_c++.lb b/ext/gcc/module_c++.lb index 38bf14d6ce..4543a53830 100644 --- a/ext/gcc/module_c++.lb +++ b/ext/gcc/module_c++.lb @@ -31,7 +31,7 @@ or: ## AVR -A partial port of GCC 8 libstdc++ is provided: +A partial port of GCC libstdc++ is provided: See https://github.com/modm-io/avr-libstdcpp. """ @@ -82,6 +82,7 @@ def build(env): "with_exceptions": with_exceptions, "with_threadsafe_statics": with_threadsafe_statics, "with_memory_traits": env.has_module(":architecture:memory"), + "with_heap": env.has_module(":platform:heap"), "is_avr": is_avr, } env.outbasepath = "modm/ext/gcc" diff --git a/ext/gcc/new_delete.cpp.in b/ext/gcc/new_delete.cpp.in index a198a9f813..a18433bfb8 100644 --- a/ext/gcc/new_delete.cpp.in +++ b/ext/gcc/new_delete.cpp.in @@ -101,17 +101,28 @@ void* operator new[](std::size_t size, modm::MemoryTraits traits, const std::not %% endif // ---------------------------------------------------------------------------- +extern "C" modm_weak +void operator_delete(modm_unused void* ptr) +{ +%% if with_heap + free(ptr); +%% else + modm_assert_continue_fail_debug(0, "delete", + "operator delete was called without heap implementation!", ptr); +%% endif +} + modm_weak -void operator delete (void *ptr) noexcept { free(ptr); } +void operator delete (void* ptr) noexcept { operator_delete(ptr); } modm_weak -void operator delete[](void* ptr) noexcept { free(ptr); } +void operator delete[](void* ptr) noexcept { operator_delete(ptr); } modm_weak -void operator delete (void* ptr, std::size_t) noexcept { free(ptr); } +void operator delete (void* ptr, std::size_t) noexcept { operator_delete(ptr); } modm_weak -void operator delete[](void* ptr, std::size_t) noexcept { free(ptr); } +void operator delete[](void* ptr, std::size_t) noexcept { operator_delete(ptr); } modm_weak -void operator delete (void* ptr, const std::nothrow_t&) noexcept { free(ptr); } +void operator delete (void* ptr, const std::nothrow_t&) noexcept { operator_delete(ptr); } modm_weak -void operator delete[](void* ptr, const std::nothrow_t&) noexcept { free(ptr); } +void operator delete[](void* ptr, const std::nothrow_t&) noexcept { operator_delete(ptr); } diff --git a/src/modm/platform/heap/cortex/module.md b/src/modm/platform/heap/cortex/module.md index ecae42f517..26975a1666 100644 --- a/src/modm/platform/heap/cortex/module.md +++ b/src/modm/platform/heap/cortex/module.md @@ -180,6 +180,22 @@ extern "C" void* _sbrk_r(struct _reent *, ptrdiff_t size) ``` +### Providing operator delete + +Unfortunately virtual C++ destructors can emit a call to `operator delete` even +for classes with static allocation and also in program without a single call to +`operator new` or `malloc`. Therefore if this module is not included, calls to +`operator delete` are ignored and you must overwrite this behavior with this +function that only points to `free`. + +```cpp +extern "C" void operator_delete(void* ptr) +{ + free(ptr); +} +``` + + ### Wrapping malloc To use a completely custom allocator, you need to replace the newlib allocator