mirror of
https://github.com/esphome/esphome.git
synced 2026-10-14 10:12:52 +00:00
Share the new_handler loop between the plain and aligned forms
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Replaces operator new for ESP-IDF builds without C++ exceptions. libstdc++'s nothrow forms call the
|
||||
* throwing form and catch std::bad_alloc, but the throw aborts here, so they abort instead of returning
|
||||
* nullptr. These forms return nullptr or abort directly, which also drops the exception class code.
|
||||
* nullptr. All forms stay in this file: --undefined=_Znwj pulls it in ahead of libstdc++.
|
||||
*/
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
@@ -15,14 +15,17 @@
|
||||
#include <new>
|
||||
#include "esp_system.h"
|
||||
|
||||
namespace esphome::esp32 {}
|
||||
namespace esphome::esp32 {} // namespace esphome::esp32
|
||||
|
||||
void *operator new(std::size_t size, const std::nothrow_t & /*tag*/) noexcept {
|
||||
namespace {
|
||||
|
||||
// Standard new_handler retry loop; returns nullptr once no handler is installed
|
||||
template<typename Alloc> void *alloc_or_null(std::size_t size, Alloc alloc) {
|
||||
// malloc(0) may return NULL, but operator new must return a unique pointer
|
||||
if (size == 0)
|
||||
size = 1;
|
||||
for (;;) {
|
||||
void *ptr = std::malloc(size); // NOLINT(cppcoreguidelines-no-malloc)
|
||||
void *ptr = alloc(size);
|
||||
if (ptr != nullptr)
|
||||
return ptr;
|
||||
std::new_handler handler = std::get_new_handler();
|
||||
@@ -32,41 +35,39 @@ void *operator new(std::size_t size, const std::nothrow_t & /*tag*/) noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
void *operator new(std::size_t size) {
|
||||
void *ptr = ::operator new(size, std::nothrow); // NOLINT: this is the nothrow form being fixed
|
||||
void *abort_if_null(void *ptr) {
|
||||
if (ptr == nullptr)
|
||||
esp_system_abort("std::bad_alloc");
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *operator new[](std::size_t size) { return ::operator new(size); }
|
||||
void *operator new[](std::size_t size, const std::nothrow_t &tag) noexcept { return ::operator new(size, tag); }
|
||||
|
||||
// Aligned forms; libstdc++'s aligned delete frees with free(), which matches memalign()
|
||||
void *operator new(std::size_t size, std::align_val_t align, const std::nothrow_t & /*tag*/) noexcept {
|
||||
if (size == 0)
|
||||
size = 1;
|
||||
for (;;) {
|
||||
void *ptr = memalign(static_cast<std::size_t>(align), size);
|
||||
if (ptr != nullptr)
|
||||
return ptr;
|
||||
std::new_handler handler = std::get_new_handler();
|
||||
if (handler == nullptr)
|
||||
return nullptr;
|
||||
handler();
|
||||
}
|
||||
void *plain_alloc(std::size_t size) {
|
||||
return alloc_or_null(size, [](std::size_t n) { return std::malloc(n); }); // NOLINT(cppcoreguidelines-no-malloc)
|
||||
}
|
||||
|
||||
// libstdc++'s aligned delete frees with free(), which matches memalign()
|
||||
void *aligned_alloc_or_null(std::size_t size, std::align_val_t align) {
|
||||
return alloc_or_null(size, [align](std::size_t n) { return memalign(static_cast<std::size_t>(align), n); });
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void *operator new(std::size_t size) { return abort_if_null(plain_alloc(size)); }
|
||||
void *operator new[](std::size_t size) { return abort_if_null(plain_alloc(size)); }
|
||||
void *operator new(std::size_t size, const std::nothrow_t & /*tag*/) noexcept { return plain_alloc(size); }
|
||||
void *operator new[](std::size_t size, const std::nothrow_t & /*tag*/) noexcept { return plain_alloc(size); }
|
||||
|
||||
void *operator new(std::size_t size, std::align_val_t align) {
|
||||
void *ptr = ::operator new(size, align, std::nothrow); // NOLINT: this is the nothrow form being fixed
|
||||
if (ptr == nullptr)
|
||||
esp_system_abort("std::bad_alloc");
|
||||
return ptr;
|
||||
return abort_if_null(aligned_alloc_or_null(size, align));
|
||||
}
|
||||
|
||||
void *operator new[](std::size_t size, std::align_val_t align) { return ::operator new(size, align); }
|
||||
void *operator new[](std::size_t size, std::align_val_t align, const std::nothrow_t &tag) noexcept {
|
||||
return ::operator new(size, align, tag);
|
||||
void *operator new[](std::size_t size, std::align_val_t align) {
|
||||
return abort_if_null(aligned_alloc_or_null(size, align));
|
||||
}
|
||||
void *operator new(std::size_t size, std::align_val_t align, const std::nothrow_t & /*tag*/) noexcept {
|
||||
return aligned_alloc_or_null(size, align);
|
||||
}
|
||||
void *operator new[](std::size_t size, std::align_val_t align, const std::nothrow_t & /*tag*/) noexcept {
|
||||
return aligned_alloc_or_null(size, align);
|
||||
}
|
||||
|
||||
#endif // CONFIG_COMPILER_CXX_EXCEPTIONS
|
||||
|
||||
+2
-3
@@ -1257,9 +1257,8 @@ def lint_no_std_bind(fname, match):
|
||||
)
|
||||
def lint_no_std_nothrow(fname, match):
|
||||
return (
|
||||
f"Please use {highlight('RAMAllocator')} from esphome/core/helpers.h instead of "
|
||||
f"{highlight('new (std::nothrow)')}: it returns nullptr on failure on every platform and lets you choose PSRAM "
|
||||
f"or internal RAM.\n"
|
||||
f"Use {highlight('RAMAllocator')} from esphome/core/helpers.h instead of {highlight('new (std::nothrow)')}; "
|
||||
f"it returns nullptr on failure on every platform and can choose PSRAM or internal RAM.\n"
|
||||
f" Before: {highlight('auto *buf = new (std::nothrow) uint8_t[n];')}\n"
|
||||
f" After: {highlight('auto buf = RAMAllocator<uint8_t>().make_unique_array_for_overwrite(n);')}\n"
|
||||
f"For one object use {highlight('RAMAllocator<T>().make_unique(args...)')}; both return empty on failure.\n"
|
||||
|
||||
Reference in New Issue
Block a user