Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Heap: Improve debug caller address reporting #8720

Open
wants to merge 41 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
4ec3c81
Lite refactoring and expanded comments
mhightower83 Nov 11, 2022
6088147
Improve caller address reporting to indicate address in
mhightower83 Nov 18, 2022
a716193
missed items
mhightower83 Nov 21, 2022
1102256
improve comments
mhightower83 Nov 22, 2022
6dfd46a
Merge branch 'master' into pr-heap-refactor3
mhightower83 Dec 5, 2022
8b3bb1f
Merge branch 'master' into pr-heap-refactor3
mhightower83 Dec 17, 2022
ea9befa
Finish merge cleanuo
mhightower83 Dec 17, 2022
3dd08be
requested changes
mhightower83 Dec 17, 2022
45f1c3b
Added missing DRAM fallback to pvPortCallocIram, pvPortZallocIram, and
mhightower83 Dec 18, 2022
57eb2b3
Add nothrow to aliases
mhightower83 Dec 18, 2022
c2590a7
Merge branch 'master' into pr-heap-refactor3
mhightower83 Dec 19, 2022
0619034
Merge branch 'pr-heap-refactor3' of github.com:mhightower83/Arduino i…
mhightower83 Dec 19, 2022
19da675
Merge branch 'master' into pr-heap-refactor3
mhightower83 Dec 19, 2022
af7b962
Merge branch 'pr-heap-refactor3' of github.com:mhightower83/Arduino i…
mhightower83 Dec 19, 2022
9423c8e
Merge branch 'master' into pr-heap-refactor3
mhightower83 Dec 22, 2022
471f838
Merge branch 'pr-heap-refactor3' of github.com:mhightower83/Arduino i…
mhightower83 Dec 22, 2022
d829540
Merge branch 'master' into pr-heap-refactor3
mhightower83 Jan 20, 2023
4c96365
Merge branch 'pr-heap-refactor3' of github.com:mhightower83/Arduino i…
mhightower83 Jan 20, 2023
840e55a
Merge branch 'master' into pr-heap-refactor3
mhightower83 Apr 18, 2023
95c7e2c
Merge branch 'master' into pr-heap-refactor3
mhightower83 Apr 27, 2023
0ce295e
Merge branch 'master' into pr-heap-refactor3
mhightower83 Apr 28, 2023
4717dcf
Use the same format for printing caller, file, line details
mhightower83 Apr 29, 2023
b083043
refactored print_loc()
mhightower83 Apr 29, 2023
ecc1b14
Merge branch 'master' into pr-heap-refactor3
mhightower83 May 2, 2023
a0044d6
Merge branch 'master' into pr-heap-refactor3
mhightower83 Jun 16, 2023
01b238a
Merge branch 'master' into pr-heap-refactor3
mhightower83 Jul 21, 2023
b5aa1de
removed unused variable from umm_local.c
mhightower83 Jul 21, 2023
1c99daf
Merge branch 'master' into pr-heap-refactor3
mhightower83 Feb 6, 2024
2bbadca
Merge branch 'master' into pr-heap-refactor3
mhightower83 Aug 30, 2024
49b48fb
Requested changes
mhightower83 Sep 3, 2024
3786ce6
Added missing "new" operators
mhightower83 Sep 5, 2024
b9a0e55
Added missing delete array operators
mhightower83 Sep 6, 2024
a5f6d7d
malloc align build cleanup - fully builds
mhightower83 Sep 8, 2024
54b034b
Correct possition of UMM_ENABLE_MEMALIGN handling in umm_malloc/umm_m…
mhightower83 Sep 12, 2024
e948329
remove static_assert checks on alignment
mhightower83 Sep 15, 2024
5653249
Updated changes to match upstream style using uncrustify.
mhightower83 Sep 17, 2024
d303d01
update comments
mhightower83 Oct 15, 2024
01a89fd
Added test Sketch for "new" and "delete" operators
mhightower83 Oct 21, 2024
0574c1a
Oops, remove external debug libary from example.
mhightower83 Oct 22, 2024
31217f6
Improved build coverage of DEV_DEBUG_ABI_CPP option and operator dele…
mhightower83 Oct 24, 2024
ecc7eed
Changed printf format from %S => %s
mhightower83 Nov 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
229 changes: 203 additions & 26 deletions cores/esp8266/abi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,42 +27,155 @@ using __cxxabiv1::__guard;

// Debugging helper, last allocation which returned NULL
extern "C" void* _heap_abi_malloc(size_t size, bool unhandled, const void* const caller);
#if UMM_ENABLE_MEMALIGN
extern "C" void* _heap_abi_memalign(size_t alignment, size_t size, bool unhandled, const void* const caller);
#endif

extern "C" void __cxa_pure_virtual(void) __attribute__ ((__noreturn__));
extern "C" void __cxa_deleted_virtual(void) __attribute__ ((__noreturn__));

#if defined(__cpp_exceptions) && (defined(DEBUG_ESP_OOM) \
|| defined(DEBUG_ESP_PORT) || defined(DEBUG_ESP_WITHINISR) || defined(MIN_ESP_OOM))

/*
When built with C++ Exceptions: "enabled", track caller address of Last OOM.
* For debug build, force enable Last OOM tracking.
* With the option "DEBUG_ESP_OOM," always do Last OOM tracking.
* Otherwise, disable Last OOM tracking. The build relies on the weak link to
the default C++ exception handler. This saves about 232 bytes of IROM, when
using C++ exceptions.

//C C++ Exception "enabled" already adds 28,868 bytes to the build does another
//C 232 matter that much? Added define MIN_ESP_OOM for experimention.

If desired, define MIN_ESP_OOM to continue with a minimum OOM tracking for
C++ exception builds.
This is what I perceived to be the intent of the original code.

Use C++ "Replaceable allocation functions" to install debug wrappers to catch
additional information for debugging. The default C++ exception handlers use
weak links.

C++ Exceptions: "enabled" -
* With debug (eg. "Debug port: Serial"), do full caller info capture and
Heap debug checks. "Replaceable allocation functions" are in use by the
debugging code. "Replaceable allocation functions" are not available to
the Sketch.
* Without debug, no OOM details captured. The C++ "Replaceable allocation
functions" are available to the Sketch.

C++ Exceptions: "disabled" -
* C++ "Replaceable allocation functions" are always in use.
* With debug, do full caller info capture and Heap debug checks.
* Without debug, capture minimum OOM information. Calling address and size
of last alloc failure.
*/

#if defined(__cpp_exceptions) && \
(defined(DEBUG_ESP_OOM) || defined(DEBUG_ESP_PORT) || defined(DEBUG_ESP_WITHINISR) || defined(MIN_ESP_OOM))

// Debug replacement adaptation from ".../new_op.cc".
using std::new_handler;
using std::bad_alloc;

static void* _heap_new(std::size_t size, const void* caller)
#if defined(UMM_ENABLE_MEMALIGN)

// Includes C++ exceptions
// Includes C++17 operator new align variants

static void* _heap_new_align(std::size_t size, std::size_t alignment, const void* caller)
{
/*
"Alignment must be a power of two."
The C++ sample code did this: if (__builtin_expect(!std::__has_single_bit(alignment), false)) throw(bad_alloc());

From https://en.cppreference.com/w/cpp/memory/c/aligned_alloc
"alignment - specifies the alignment. Must be a valid alignment
supported by the implementation."

I leave the validation to the umm_malloc library. See umm_memalign() for
details. Generally speaking, zero is handled as default and the default
is sizeof(umm_block), 8-bytes.
*/

void* p;

/* malloc (0) is unpredictable; avoid it. */
if (__builtin_expect(size == 0, false)) {
size = 1;
while (nullptr == (p = _heap_abi_memalign(alignment, size, false, caller))) {
new_handler handler = std::get_new_handler();
if (!handler) {
throw(bad_alloc());
}
handler();
}

return p;
}


// new_opa
void* operator new (std::size_t size, std::align_val_t alignment)
{
return _heap_new_align(size, std::size_t(alignment), __builtin_return_address(0));
}

// new_opva
void* operator new[] (std::size_t size, std::align_val_t alignment)
{
return _heap_new_align(size, std::size_t(alignment), __builtin_return_address(0));
}

// new_opant
void* operator new (std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept
{
__try {
return _heap_new_align(size, std::size_t(alignment), __builtin_return_address(0));
}
__catch(...) {
return nullptr;
}
}

// new_opvant
void* operator new[] (std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept
{
__try {
return _heap_new_align(size, std::size_t(alignment), __builtin_return_address(0));
}
__catch(...) {
return nullptr;
}
}

while (0 == (p = _heap_abi_malloc(size, false, caller))) {
// new_op
void* operator new (std::size_t size)
{
return _heap_new_align(size, __STDCPP_DEFAULT_NEW_ALIGNMENT__, __builtin_return_address(0));
}

// new_opv
void* operator new[] (std::size_t size)
{
return _heap_new_align(size, __STDCPP_DEFAULT_NEW_ALIGNMENT__, __builtin_return_address(0));
}

// new_opnt
void* operator new (size_t size, const std::nothrow_t&) noexcept
{
__try {
return _heap_new_align(size, __STDCPP_DEFAULT_NEW_ALIGNMENT__, __builtin_return_address(0));
}
__catch (...) {
return nullptr;
}
}

// new_opvnt
void* operator new[] (size_t size, const std::nothrow_t&) noexcept
{
__try {
return _heap_new_align(size, __STDCPP_DEFAULT_NEW_ALIGNMENT__, __builtin_return_address(0));
}
__catch (...) {
return nullptr;
}
}

#else // ! UMM_ENABLE_MEMALIGN

// Includes C++ exceptions
// Without C++17 operator new align variants

static void* _heap_new(std::size_t size, const void* caller)
{
void* p;

while (nullptr == (p = _heap_abi_malloc(size, false, caller))) {
new_handler handler = std::get_new_handler();
if (!handler) {
throw(bad_alloc());
Expand Down Expand Up @@ -102,19 +215,64 @@ void* operator new[] (size_t size, const std::nothrow_t&) noexcept
return nullptr;
}
}
/*
TODO:
Current master does not support "new" align operations. Compiler reports:
"/workdir/repo/gcc-gnu/libstdc++-v3/libsupc++/new_opa.cc:86: undefined reference to `memalign'"
Look at enhancement to umm_malloc for an alignment option.
*/
#endif // #if UMM_ENABLE_MEMALIGN

#elif !defined(__cpp_exceptions)
// When doing builds with C++ Exceptions "disabled", always save details of
// the last OOM event.

// overwrite weak operators new/new[] definitions

#if defined(UMM_ENABLE_MEMALIGN)

// Without C++ exceptions
// Includes C++17 operator new align variants

void* operator new (size_t size, std::align_val_t alignment)
{
return _heap_abi_memalign(std::size_t(alignment), size, true, __builtin_return_address(0));
}

void* operator new[] (size_t size, std::align_val_t alignment)
{
return _heap_abi_memalign(std::size_t(alignment), size, true, __builtin_return_address(0));
}

void* operator new (size_t size, std::align_val_t alignment, const std::nothrow_t&)
{
return _heap_abi_memalign(std::size_t(alignment), size, false, __builtin_return_address(0));
}

void* operator new[] (size_t size, std::align_val_t alignment, const std::nothrow_t&)
{
return _heap_abi_memalign(std::size_t(alignment), size, false, __builtin_return_address(0));
}

void* operator new (size_t size)
{
return _heap_abi_memalign(__STDCPP_DEFAULT_NEW_ALIGNMENT__, size, true, __builtin_return_address(0));
}

void* operator new[] (size_t size)
{
return _heap_abi_memalign(__STDCPP_DEFAULT_NEW_ALIGNMENT__, size, true, __builtin_return_address(0));
}

void* operator new (size_t size, const std::nothrow_t&)
{
return _heap_abi_memalign(__STDCPP_DEFAULT_NEW_ALIGNMENT__, size, false, __builtin_return_address(0));
}

void* operator new[] (size_t size, const std::nothrow_t&)
{
return _heap_abi_memalign(__STDCPP_DEFAULT_NEW_ALIGNMENT__, size, false, __builtin_return_address(0));
}

#else

// Without C++ exceptions
// Without C++17 operator new align variants

void* operator new (size_t size)
{
return _heap_abi_malloc(size, true, __builtin_return_address(0));
Expand All @@ -134,8 +292,27 @@ void* operator new[] (size_t size, const std::nothrow_t&)
{
return _heap_abi_malloc(size, false, __builtin_return_address(0));
}
#endif // #elif !defined(__cpp_exceptions) #if defined(UMM_ENABLE_MEMALIGN)
#else
/*
Using weaklink C++ Exception handlers in libstdc
The "new" operators that express alignment should work through libstdc via
memalign() in the umm_malloc library.

This saves 20 bytes in the UMM_ENABLE_MEMALIGN=1 case and 32 bytes when
UMM_ENABLE_MEMALIGN=0.

*/
//D <<
//C temporary pragmas remove before merge
#pragma message("Using weaklink C++ Exception handlers in libstdc")
#if UMM_ENABLE_MEMALIGN
#pragma message("The \"new\" operators that express alignment should work through libstdc via memalign() in the umm_malloc library.")
//D >>
#endif

#endif // #if defined(__cpp_exceptions)

#endif // !defined(__cpp_exceptions)

void __cxa_pure_virtual(void)
{
Expand Down
Loading