From ee4d15d02f8359b3de40aaaad53ca2a1c407cf0f Mon Sep 17 00:00:00 2001 From: tgotic Date: Sun, 7 Aug 2022 16:21:22 +0200 Subject: [PATCH 1/2] fix malloc(0) and heap_caps_alloc_failed() Don't call heap_caps_alloc_failed() for malloc(0) and calloc(0), because it is not an error. Improve handling of malloc(0) and calloc(0). Merges https://github.com/espressif/esp-idf/pull/9517 --- components/heap/heap_caps.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/components/heap/heap_caps.c b/components/heap/heap_caps.c index 516c00cc715a..3b6b2f3c2de0 100644 --- a/components/heap/heap_caps.c +++ b/components/heap/heap_caps.c @@ -62,9 +62,9 @@ static void heap_caps_alloc_failed(size_t requested_size, uint32_t caps, const c alloc_failed_callback(requested_size, caps, function_name); } - #ifdef CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS +#ifdef CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS esp_system_abort("Memory allocation failed"); - #endif +#endif } esp_err_t heap_caps_register_failed_alloc_callback(esp_alloc_failed_hook_t callback) @@ -92,6 +92,10 @@ IRAM_ATTR static void *heap_caps_malloc_base( size_t size, uint32_t caps) { void *ret = NULL; + if (size == 0) { + return NULL; + } + if (size > HEAP_SIZE_MAX) { // Avoids int overflow when adding small numbers to size, or // calculating 'end' from start+size, by limiting 'size' to the possible range @@ -161,7 +165,7 @@ IRAM_ATTR void *heap_caps_malloc( size_t size, uint32_t caps){ void* ptr = heap_caps_malloc_base(size, caps); - if (!ptr){ + if (!ptr && size > 0){ heap_caps_alloc_failed(size, caps, __func__); } @@ -196,13 +200,13 @@ IRAM_ATTR void *heap_caps_malloc_default( size_t size ) } else { r=heap_caps_malloc_base( size, MALLOC_CAP_DEFAULT | MALLOC_CAP_SPIRAM ); } - if (r==NULL) { + if (r==NULL && size > 0) { //try again while being less picky r=heap_caps_malloc_base( size, MALLOC_CAP_DEFAULT ); } // allocation failure? - if (r==NULL){ + if (r==NULL && size > 0){ heap_caps_alloc_failed(size, MALLOC_CAP_DEFAULT, __func__); } @@ -259,7 +263,7 @@ IRAM_ATTR void *heap_caps_malloc_prefer( size_t size, size_t num, ... ) break; } } - if (r == NULL){ + if (r == NULL && size > 0){ heap_caps_alloc_failed(size, caps, __func__); } va_end( argp ); @@ -282,7 +286,7 @@ IRAM_ATTR void *heap_caps_realloc_prefer( void *ptr, size_t size, size_t num, .. break; } } - if (r == NULL){ + if (r == NULL && size > 0){ heap_caps_alloc_failed(size, caps, __func__); } va_end( argp ); @@ -301,11 +305,11 @@ IRAM_ATTR void *heap_caps_calloc_prefer( size_t n, size_t size, size_t num, ... while (num--) { caps = va_arg( argp, uint32_t ); r = heap_caps_calloc_base( n, size, caps ); - if (r != NULL){ + if (r != NULL || size == 0){ break; } } - if (r == NULL){ + if (r == NULL && size > 0){ heap_caps_alloc_failed(size, caps, __func__); } va_end( argp ); @@ -462,7 +466,7 @@ IRAM_ATTR void *heap_caps_calloc( size_t n, size_t size, uint32_t caps) { void* ptr = heap_caps_calloc_base(n, size, caps); - if (!ptr){ + if (!ptr && size > 0){ heap_caps_alloc_failed(size, caps, __func__); } @@ -624,6 +628,10 @@ IRAM_ATTR void *heap_caps_aligned_alloc(size_t alignment, size_t size, uint32_t return NULL; } + if (size == 0) { + return NULL; + } + if (size > HEAP_SIZE_MAX) { // Avoids int overflow when adding small numbers to size, or // calculating 'end' from start+size, by limiting 'size' to the possible range From c6ddf7288cf401344e88f9584672a6a664da6007 Mon Sep 17 00:00:00 2001 From: Omar Chebib Date: Mon, 8 Aug 2022 15:39:25 +0800 Subject: [PATCH 2/2] heap: add a unit test for malloc(0) and slightly optimize heap_caps_malloc_prefer --- components/heap/heap_caps.c | 2 +- components/heap/test/test_malloc.c | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/components/heap/heap_caps.c b/components/heap/heap_caps.c index 3b6b2f3c2de0..9c35b56a810c 100644 --- a/components/heap/heap_caps.c +++ b/components/heap/heap_caps.c @@ -259,7 +259,7 @@ IRAM_ATTR void *heap_caps_malloc_prefer( size_t size, size_t num, ... ) while (num--) { caps = va_arg( argp, uint32_t ); r = heap_caps_malloc_base( size, caps ); - if (r != NULL) { + if (r != NULL || size == 0) { break; } } diff --git a/components/heap/test/test_malloc.c b/components/heap/test/test_malloc.c index 6f4bbd872884..995a64da3387 100644 --- a/components/heap/test/test_malloc.c +++ b/components/heap/test/test_malloc.c @@ -132,3 +132,25 @@ TEST_CASE("malloc(0) should return a NULL pointer", "[heap]") p = malloc(0); TEST_ASSERT(p == NULL); } + +static bool failure_occured = false; + +static void test_alloc_failure_callback(size_t size, uint32_t caps, const char * function_name) +{ + failure_occured = true; +} + +TEST_CASE("malloc/calloc(0) should not call failure callback", "[heap]") +{ + void* ptr = NULL; + esp_err_t ret = heap_caps_register_failed_alloc_callback(test_alloc_failure_callback); + TEST_ASSERT(ret == ESP_OK); + ptr = malloc(0); + TEST_ASSERT_NULL(ptr); + /* Check that our callback was NOT called */ + TEST_ASSERT_FALSE(failure_occured); + /* Do the same thing for calloc */ + ptr = calloc(0, 0); + TEST_ASSERT_NULL(ptr); + TEST_ASSERT_FALSE(failure_occured); +}