diff --git a/components/heap/CMakeLists.txt b/components/heap/CMakeLists.txt index 0110a19d7d..40f75860a8 100644 --- a/components/heap/CMakeLists.txt +++ b/components/heap/CMakeLists.txt @@ -27,7 +27,7 @@ list(APPEND srcs "port/${target}/memory_layout.c") idf_component_register(SRCS "${srcs}" INCLUDE_DIRS include LDFRAGMENTS linker.lf - PRIV_REQUIRES soc spi_flash) + PRIV_REQUIRES soc) if(CONFIG_HEAP_TRACING) set(WRAP_FUNCTIONS diff --git a/components/heap/heap_caps.c b/components/heap/heap_caps.c index bc29bb38db..7258c0af3c 100644 --- a/components/heap/heap_caps.c +++ b/components/heap/heap_caps.c @@ -22,7 +22,6 @@ #include "esp_log.h" #include "heap_private.h" #include "esp_system.h" -#include "esp_private/cache_utils.h" /* Forward declaration for base function, put in IRAM. * These functions don't check for errors after trying to allocate memory. */ @@ -64,16 +63,10 @@ IRAM_ATTR static void *dram_alloc_to_iram_addr(void *addr, size_t len) } -IRAM_ATTR static void heap_caps_alloc_failed(size_t requested_size, uint32_t caps, const char *function_name) +IRAM_ATTR NOINLINE_ATTR static void heap_caps_alloc_failed(size_t requested_size, uint32_t caps, const char *function_name) { - static const DRAM_ATTR char *default_func_name = ""; if (alloc_failed_callback) { - if (!spi_flash_cache_enabled() && !esp_ptr_internal(function_name)) { - alloc_failed_callback(requested_size, caps, default_func_name); - } - else { - alloc_failed_callback(requested_size, caps, function_name); - } + alloc_failed_callback(requested_size, caps, function_name); } #ifdef CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS diff --git a/components/heap/linker.lf b/components/heap/linker.lf index 6c1050b41a..33e1092d35 100644 --- a/components/heap/linker.lf +++ b/components/heap/linker.lf @@ -14,7 +14,6 @@ entries: heap_tlsf:tlsf_free (noflash) heap_tlsf:tlsf_realloc (noflash) - multi_heap:assert_valid_block (noflash) multi_heap:multi_heap_get_block_address_impl (noflash) multi_heap:multi_heap_get_allocated_size_impl (noflash) multi_heap:multi_heap_set_lock (noflash) @@ -26,6 +25,9 @@ entries: multi_heap:multi_heap_realloc_impl (noflash) multi_heap:multi_heap_aligned_alloc_impl_offs (noflash) multi_heap:multi_heap_aligned_alloc_impl (noflash) + multi_heap:multi_heap_internal_lock (noflash) + multi_heap:multi_heap_internal_unlock (noflash) + multi_heap:assert_valid_block (noflash) if HEAP_POISONING_DISABLED = n: multi_heap_poisoning:poison_allocated_region (noflash) @@ -41,5 +43,5 @@ entries: multi_heap_poisoning:multi_heap_internal_check_block_poisoning (noflash) multi_heap_poisoning:multi_heap_internal_poison_fill_region (noflash) - if HEAP_POISONING_COMPREHENSIVE = y: - multi_heap_poisoning:verify_fill_pattern (noflash) + if HEAP_POISONING_COMPREHENSIVE = y: + multi_heap_poisoning:verify_fill_pattern (noflash) diff --git a/components/heap/multi_heap.c b/components/heap/multi_heap.c index fd7183ac27..e5c8647f17 100644 --- a/components/heap/multi_heap.c +++ b/components/heap/multi_heap.c @@ -86,7 +86,7 @@ typedef struct multi_heap_info { } heap_t; /* Check a block is valid for this heap. Used to verify parameters. */ -static void assert_valid_block(const heap_t *heap, const block_header_t *block) +__attribute__((noinline)) NOCLONE_ATTR static void assert_valid_block(const heap_t *heap, const block_header_t *block) { pool_t pool = tlsf_get_pool(heap->heap_data); void *ptr = block_to_ptr(block); @@ -137,12 +137,12 @@ void multi_heap_set_lock(multi_heap_handle_t heap, void *lock) heap->lock = lock; } -void inline multi_heap_internal_lock(multi_heap_handle_t heap) +void multi_heap_internal_lock(multi_heap_handle_t heap) { MULTI_HEAP_LOCK(heap->lock); } -void inline multi_heap_internal_unlock(multi_heap_handle_t heap) +void multi_heap_internal_unlock(multi_heap_handle_t heap) { MULTI_HEAP_UNLOCK(heap->lock); } @@ -333,7 +333,7 @@ bool multi_heap_check(multi_heap_handle_t heap, bool print_errors) return valid; } -static void multi_heap_dump_tlsf(void* ptr, size_t size, int used, void* user) +__attribute__((noinline)) static void multi_heap_dump_tlsf(void* ptr, size_t size, int used, void* user) { (void)user; MULTI_HEAP_STDERR_PRINTF("Block %p data, size: %d bytes, Free: %s \n", @@ -370,7 +370,7 @@ size_t multi_heap_minimum_free_size_impl(multi_heap_handle_t heap) return heap->minimum_free_bytes; } -static void multi_heap_get_info_tlsf(void* ptr, size_t size, int used, void* user) +__attribute__((noinline)) static void multi_heap_get_info_tlsf(void* ptr, size_t size, int used, void* user) { multi_heap_info_t *info = user; diff --git a/components/heap/multi_heap_internal.h b/components/heap/multi_heap_internal.h index 5be4dee608..131c60e27d 100644 --- a/components/heap/multi_heap_internal.h +++ b/components/heap/multi_heap_internal.h @@ -13,6 +13,14 @@ // limitations under the License. #pragma once +/* Define a noclone attribute when compiled with GCC as certain functions + * in the heap component should not be cloned by the compiler */ +#if defined __has_attribute && __has_attribute(noclone) +#define NOCLONE_ATTR __attribute((noclone)) +#else +#define NOCLONE_ATTR +#endif + /* Opaque handle to a heap block */ typedef const struct block_header_t *multi_heap_block_handle_t; diff --git a/components/heap/multi_heap_poisoning.c b/components/heap/multi_heap_poisoning.c index ca27f3f290..4b2d9bae2a 100644 --- a/components/heap/multi_heap_poisoning.c +++ b/components/heap/multi_heap_poisoning.c @@ -65,7 +65,7 @@ typedef struct { Returns the pointer to the actual usable data buffer (ie after 'head') */ -static uint8_t *poison_allocated_region(poison_head_t *head, size_t alloc_size) +__attribute__((noinline)) static uint8_t *poison_allocated_region(poison_head_t *head, size_t alloc_size) { uint8_t *data = (uint8_t *)(&head[1]); /* start of data ie 'real' allocated buffer */ poison_tail_t *tail = (poison_tail_t *)(data + alloc_size); @@ -89,7 +89,7 @@ static uint8_t *poison_allocated_region(poison_head_t *head, size_t alloc_size) Returns a pointer to the poison header structure, or NULL if the poison structures are corrupt. */ -static poison_head_t *verify_allocated_region(void *data, bool print_errors) +__attribute__((noinline)) static poison_head_t *verify_allocated_region(void *data, bool print_errors) { poison_head_t *head = (poison_head_t *)((intptr_t)data - sizeof(poison_head_t)); poison_tail_t *tail = (poison_tail_t *)((intptr_t)data + head->alloc_size); @@ -131,8 +131,12 @@ static poison_head_t *verify_allocated_region(void *data, bool print_errors) if swap_pattern is true, swap patterns in the buffer (ie replace MALLOC_FILL_PATTERN with FREE_FILL_PATTERN, and vice versa.) Returns true if verification checks out. + + This function has the attribute noclone to prevent the compiler to create a clone on flash where expect_free is removed (as this + function is called only with expect_free == true throughout the component). */ -static bool verify_fill_pattern(void *data, size_t size, bool print_errors, bool expect_free, bool swap_pattern) +__attribute__((noinline)) NOCLONE_ATTR +static bool verify_fill_pattern(void *data, size_t size, const bool print_errors, const bool expect_free, bool swap_pattern) { const uint32_t FREE_FILL_WORD = (FREE_FILL_PATTERN << 24) | (FREE_FILL_PATTERN << 16) | (FREE_FILL_PATTERN << 8) | FREE_FILL_PATTERN; const uint32_t MALLOC_FILL_WORD = (MALLOC_FILL_PATTERN << 24) | (MALLOC_FILL_PATTERN << 16) | (MALLOC_FILL_PATTERN << 8) | MALLOC_FILL_PATTERN; @@ -242,7 +246,9 @@ void *multi_heap_malloc(multi_heap_handle_t heap, size_t size) return data; } -void multi_heap_free(multi_heap_handle_t heap, void *p) +/* This function has the noclone attribute to prevent the compiler to optimize out the + * check for p == NULL and create a clone function placed in flash. */ +NOCLONE_ATTR void multi_heap_free(multi_heap_handle_t heap, void *p) { if (p == NULL) { return;