heap_caps: added special case for realloc when previous area is an diram_iram ptr, this will force a malloc/copy/free

This commit is contained in:
Felipe Neves 2019-11-19 15:36:22 -03:00
parent ce9f84fba9
commit 31145f38fa
2 changed files with 31 additions and 27 deletions

View file

@ -275,6 +275,10 @@ IRAM_ATTR void heap_caps_free( void *ptr)
IRAM_ATTR void *heap_caps_realloc( void *ptr, size_t size, int caps)
{
bool ptr_in_diram_case = false;
heap_t *heap = NULL;
void *dram_ptr = NULL;
if (ptr == NULL) {
return heap_caps_malloc(size, caps);
}
@ -288,23 +292,32 @@ IRAM_ATTR void *heap_caps_realloc( void *ptr, size_t size, int caps)
return NULL;
}
//On esp32s2 the pointer to heap may be aliased, we need to
//The pointer to memory may be aliased, we need to
//recover it before to manage a new allocation:
if(esp_ptr_in_diram_iram((void *)ptr)) {
//pointer must be already aliased, otherwise just ignore this part:
uint32_t *dram_addr = (uint32_t *)ptr;
ptr = (void *)dram_addr[-1];
dram_ptr = (void *)dram_addr[-1];
//printf("[HEAP_CAPS_MALLOC]: obtained pointer that was aliased: %p \n", (void *)ptr);
heap = find_containing_heap(dram_ptr);
assert(heap != NULL && "realloc() pointer is outside heap areas");
//with pointers that reside on diram space, we avoid to
//to use realloc implementation due to address translation issues,
//instead force a malloc/copy/free
ptr_in_diram_case = true;
} else {
heap = find_containing_heap(ptr);
assert(heap != NULL && "realloc() pointer is outside heap areas");
}
heap_t *heap = find_containing_heap(ptr);
assert(heap != NULL && "realloc() pointer is outside heap areas");
// are the existing heap's capabilities compatible with the
// requested ones?
bool compatible_caps = (caps & get_all_caps(heap)) == caps;
if (compatible_caps) {
if (compatible_caps && !ptr_in_diram_case) {
// try to reallocate this memory within the same heap
// (which will resize the block if it can)
void *r = multi_heap_realloc(heap->heap, ptr, size);
@ -317,8 +330,16 @@ IRAM_ATTR void *heap_caps_realloc( void *ptr, size_t size, int caps)
// in a different heap with requested capabilities.
void *new_p = heap_caps_malloc(size, caps);
if (new_p != NULL) {
size_t old_size = 0;
//If we're dealing with aliased ptr, information regarding its containing
//heap can only be obtained with translated address.
if(ptr_in_diram_case) {
old_size = multi_heap_get_allocated_size(heap->heap, dram_ptr);
} else {
old_size = multi_heap_get_allocated_size(heap->heap, ptr);
}
size_t old_size = multi_heap_get_allocated_size(heap->heap, ptr);
assert(old_size > 0);
memcpy(new_p, ptr, MIN(size, old_size));
heap_caps_free(ptr);

View file

@ -21,10 +21,6 @@
#include <sys/param.h>
#include <multi_heap.h>
#include "multi_heap_internal.h"
#if CONFIG_IDF_TARGET_ESP32S2BETA
#include "heap_private.h"
#endif
/* Note: Keep platform-specific parts in this header, this source
file should depend on libc only */
@ -272,21 +268,8 @@ void *multi_heap_realloc(multi_heap_handle_t heap, void *p, size_t size)
new_head = multi_heap_malloc_impl(heap, size + POISON_OVERHEAD);
if (new_head != NULL) {
result = poison_allocated_region(new_head, size);
#if CONFIG_IDF_TARGET_ESP32S2BETA
//We may need to deal with aliased heap pointers. here too,
//mainly because the heap canary is located before the
//the slot reserved to preserve original DRAM address
//so the original user data is actually p + 4 ahead :
if(esp_ptr_in_diram_dram((void *)p)) {
memcpy(result, p + sizeof(intptr_t), MIN(size, orig_alloc_size));
} else {
memcpy(result, p , MIN(size, orig_alloc_size));
}
#else
memcpy(result, p, MIN(size, orig_alloc_size));
#endif
multi_heap_free(heap, p);
memcpy(result, p, MIN(size, orig_alloc_size));
multi_heap_free(heap, p);
}
#endif