Merge branch 'staging/fix_heap_fail_callback_v4.4' into 'release/v4.4'

Heap: heap_caps_*_prefer functions now properly call alloc_failed callback (backport v4.4)

See merge request espressif/esp-idf!19481
This commit is contained in:
Ivan Grokhotkov
2022-08-11 06:28:03 +08:00
2 changed files with 79 additions and 17 deletions

View File

@@ -24,8 +24,11 @@
#include "esp_system.h" #include "esp_system.h"
// forward declaration /* Forward declaration for base function, put in IRAM.
IRAM_ATTR static void *heap_caps_realloc_base( void *ptr, size_t size, uint32_t caps); * These functions don't check for errors after trying to allocate memory. */
static void *heap_caps_realloc_base( void *ptr, size_t size, uint32_t caps );
static void *heap_caps_calloc_base( size_t n, size_t size, uint32_t caps );
static void *heap_caps_malloc_base( size_t size, uint32_t caps );
/* /*
This file, combined with a region allocator that supports multiple heaps, solves the problem that the ESP32 has RAM This file, combined with a region allocator that supports multiple heaps, solves the problem that the ESP32 has RAM
@@ -97,6 +100,10 @@ IRAM_ATTR static void *heap_caps_malloc_base( size_t size, uint32_t caps)
{ {
void *ret = NULL; void *ret = NULL;
if (size == 0) {
return NULL;
}
if (size > HEAP_SIZE_MAX) { if (size > HEAP_SIZE_MAX) {
// Avoids int overflow when adding small numbers to size, or // Avoids int overflow when adding small numbers to size, or
// calculating 'end' from start+size, by limiting 'size' to the possible range // calculating 'end' from start+size, by limiting 'size' to the possible range
@@ -166,7 +173,7 @@ IRAM_ATTR void *heap_caps_malloc( size_t size, uint32_t caps){
void* ptr = heap_caps_malloc_base(size, caps); void* ptr = heap_caps_malloc_base(size, caps);
if (!ptr){ if (!ptr && size > 0){
heap_caps_alloc_failed(size, caps, __func__); heap_caps_alloc_failed(size, caps, __func__);
} }
@@ -201,13 +208,13 @@ IRAM_ATTR void *heap_caps_malloc_default( size_t size )
} else { } else {
r=heap_caps_malloc_base( size, MALLOC_CAP_DEFAULT | MALLOC_CAP_SPIRAM ); 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 //try again while being less picky
r=heap_caps_malloc_base( size, MALLOC_CAP_DEFAULT ); r=heap_caps_malloc_base( size, MALLOC_CAP_DEFAULT );
} }
// allocation failure? // allocation failure?
if (r==NULL){ if (r==NULL && size > 0){
heap_caps_alloc_failed(size, MALLOC_CAP_DEFAULT, __func__); heap_caps_alloc_failed(size, MALLOC_CAP_DEFAULT, __func__);
} }
@@ -256,13 +263,17 @@ IRAM_ATTR void *heap_caps_malloc_prefer( size_t size, size_t num, ... )
va_list argp; va_list argp;
va_start( argp, num ); va_start( argp, num );
void *r = NULL; void *r = NULL;
uint32_t caps = MALLOC_CAP_DEFAULT;
while (num--) { while (num--) {
uint32_t caps = va_arg( argp, uint32_t ); caps = va_arg( argp, uint32_t );
r = heap_caps_malloc( size, caps ); r = heap_caps_malloc_base( size, caps );
if (r != NULL) { if (r != NULL || size == 0) {
break; break;
} }
} }
if (r == NULL && size > 0){
heap_caps_alloc_failed(size, caps, __func__);
}
va_end( argp ); va_end( argp );
return r; return r;
} }
@@ -275,13 +286,17 @@ IRAM_ATTR void *heap_caps_realloc_prefer( void *ptr, size_t size, size_t num, ..
va_list argp; va_list argp;
va_start( argp, num ); va_start( argp, num );
void *r = NULL; void *r = NULL;
uint32_t caps = MALLOC_CAP_DEFAULT;
while (num--) { while (num--) {
uint32_t caps = va_arg( argp, uint32_t ); caps = va_arg( argp, uint32_t );
r = heap_caps_realloc( ptr, size, caps ); r = heap_caps_realloc_base( ptr, size, caps );
if (r != NULL || size == 0) { if (r != NULL || size == 0) {
break; break;
} }
} }
if (r == NULL && size > 0){
heap_caps_alloc_failed(size, caps, __func__);
}
va_end( argp ); va_end( argp );
return r; return r;
} }
@@ -294,10 +309,16 @@ IRAM_ATTR void *heap_caps_calloc_prefer( size_t n, size_t size, size_t num, ...
va_list argp; va_list argp;
va_start( argp, num ); va_start( argp, num );
void *r = NULL; void *r = NULL;
uint32_t caps = MALLOC_CAP_DEFAULT;
while (num--) { while (num--) {
uint32_t caps = va_arg( argp, uint32_t ); caps = va_arg( argp, uint32_t );
r = heap_caps_calloc( n, size, caps ); r = heap_caps_calloc_base( n, size, caps );
if (r != NULL) break; if (r != NULL || size == 0){
break;
}
}
if (r == NULL && size > 0){
heap_caps_alloc_failed(size, caps, __func__);
} }
va_end( argp ); va_end( argp );
return r; return r;
@@ -429,7 +450,11 @@ IRAM_ATTR void *heap_caps_realloc( void *ptr, size_t size, uint32_t caps)
return ptr; return ptr;
} }
IRAM_ATTR void *heap_caps_calloc( size_t n, size_t size, uint32_t caps) /*
This function should not be called directly as it does not
check for failure / call heap_caps_alloc_failed()
*/
IRAM_ATTR static void *heap_caps_calloc_base( size_t n, size_t size, uint32_t caps)
{ {
void *result; void *result;
size_t size_bytes; size_t size_bytes;
@@ -438,13 +463,24 @@ IRAM_ATTR void *heap_caps_calloc( size_t n, size_t size, uint32_t caps)
return NULL; return NULL;
} }
result = heap_caps_malloc(size_bytes, caps); result = heap_caps_malloc_base(size_bytes, caps);
if (result != NULL) { if (result != NULL) {
bzero(result, size_bytes); bzero(result, size_bytes);
} }
return result; return result;
} }
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 && size > 0){
heap_caps_alloc_failed(size, caps, __func__);
}
return ptr;
}
size_t heap_caps_get_total_size(uint32_t caps) size_t heap_caps_get_total_size(uint32_t caps)
{ {
size_t total_size = 0; size_t total_size = 0;
@@ -599,6 +635,10 @@ IRAM_ATTR void *heap_caps_aligned_alloc(size_t alignment, size_t size, uint32_t
return NULL; return NULL;
} }
if (size == 0) {
return NULL;
}
if (size > HEAP_SIZE_MAX) { if (size > HEAP_SIZE_MAX) {
// Avoids int overflow when adding small numbers to size, or // Avoids int overflow when adding small numbers to size, or
// calculating 'end' from start+size, by limiting 'size' to the possible range // calculating 'end' from start+size, by limiting 'size' to the possible range

View File

@@ -132,3 +132,25 @@ TEST_CASE("malloc(0) should return a NULL pointer", "[heap]")
p = malloc(0); p = malloc(0);
TEST_ASSERT(p == NULL); 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);
}