Merge branch 'feat/add-heap-walker-api' into 'master'

feat(heap): Add walker to the heap component

Closes IDF-9189

See merge request espressif/esp-idf!29047
pull/13550/head
Guillaume Souchere 2024-03-22 15:58:34 +08:00
commit 573bd1bcc9
20 zmienionych plików z 436 dodań i 26 usunięć

Wyświetl plik

@ -44,11 +44,16 @@ else()
endif()
endif()
if(CONFIG_HEAP_TLSF_USE_ROM_IMPL AND (CONFIG_ESP_ROM_TLSF_CHECK_PATCH OR CONFIG_HEAP_TLSF_CHECK_PATCH))
if(CONFIG_HEAP_TLSF_USE_ROM_IMPL AND CONFIG_ESP_ROM_TLSF_CHECK_PATCH)
# This file shall be included in the build if TLSF in ROM is activated
list(APPEND sources "patches/esp_rom_tlsf.c")
endif()
if(CONFIG_HEAP_TLSF_USE_ROM_IMPL AND CONFIG_ESP_ROM_MULTI_HEAP_WALK_PATCH)
# This file shall be included in the build if TLSF in ROM is activated
list(APPEND sources "patches/esp_rom_multi_heap.c")
endif()
list(APPEND private_required_comp soc hal)
endif()
@ -64,6 +69,8 @@ if(CONFIG_HAL_WDT_USE_ROM_IMPL)
list(APPEND sources "patches/esp_rom_wdt.c")
endif()
if(CONFIG_ESP_ROM_HAS_FLASH_COUNT_PAGES_BUG OR CONFIG_ESP_ROM_HAS_CACHE_WRITEBACK_BUG)
list(APPEND sources "patches/esp_rom_cache_esp32s2_esp32s3.c")
endif()
@ -216,6 +223,10 @@ else() # Regular app build
target_link_libraries(${COMPONENT_LIB} PRIVATE "-u tlsf_set_rom_patches")
endif()
if((CONFIG_ESP_ROM_TLSF_CHECK_PATCH OR CONFIG_ESP_ROM_MULTI_HEAP_WALK_PATCH))
target_link_libraries(${COMPONENT_LIB} PRIVATE "-u esp_rom_include_multi_heap_patch")
endif()
rom_linker_script("heap")
endif()

Wyświetl plik

@ -39,6 +39,14 @@ config ESP_ROM_HAS_HEAP_TLSF
bool
default y
config ESP_ROM_TLSF_CHECK_PATCH
bool
default y
config ESP_ROM_MULTI_HEAP_WALK_PATCH
bool
default y
config ESP_ROM_HAS_LAYOUT_TABLE
bool
default y

Wyświetl plik

@ -15,6 +15,8 @@
#define ESP_ROM_HAS_HAL_WDT (1) // ROM has the implementation of Watchdog HAL driver
#define ESP_ROM_HAS_HAL_SYSTIMER (1) // ROM has the implementation of Systimer HAL driver
#define ESP_ROM_HAS_HEAP_TLSF (1) // ROM has the implementation of the tlsf and multi-heap library
#define ESP_ROM_TLSF_CHECK_PATCH (1) // ROM does not contain the patch of tlsf_check_pool()
#define ESP_ROM_MULTI_HEAP_WALK_PATCH (1) // ROM does not contain the patch of multi_heap_walk()
#define ESP_ROM_HAS_LAYOUT_TABLE (1) // ROM has the layout table
#define ESP_ROM_HAS_SPI_FLASH (1) // ROM has the implementation of SPI Flash driver
#define ESP_ROM_HAS_NEWLIB (1) // ROM has newlib (at least parts of it) functions included

Wyświetl plik

@ -51,6 +51,10 @@ config ESP_ROM_TLSF_CHECK_PATCH
bool
default y
config ESP_ROM_MULTI_HEAP_WALK_PATCH
bool
default y
config ESP_ROM_HAS_LAYOUT_TABLE
bool
default y

Wyświetl plik

@ -18,6 +18,7 @@
#define ESP_ROM_HAS_HAL_SYSTIMER (1) // ROM has the implementation of Systimer HAL driver
#define ESP_ROM_HAS_HEAP_TLSF (1) // ROM has the implementation of the tlsf and multi-heap library
#define ESP_ROM_TLSF_CHECK_PATCH (1) // ROM does not contain the patch of tlsf_check_pool()
#define ESP_ROM_MULTI_HEAP_WALK_PATCH (1) // ROM does not contain the patch of multi_heap_walk()
#define ESP_ROM_HAS_LAYOUT_TABLE (1) // ROM has the layout table
#define ESP_ROM_HAS_SPI_FLASH (1) // ROM has the implementation of SPI Flash driver
#define ESP_ROM_WITHOUT_REGI2C (1) // ROM has no regi2c APIs

Wyświetl plik

@ -51,6 +51,10 @@ config ESP_ROM_TLSF_CHECK_PATCH
bool
default y
config ESP_ROM_MULTI_HEAP_WALK_PATCH
bool
default y
config ESP_ROM_HAS_LAYOUT_TABLE
bool
default y

Wyświetl plik

@ -18,6 +18,7 @@
#define ESP_ROM_HAS_HAL_SYSTIMER (1) // ROM has the implementation of Systimer HAL driver
#define ESP_ROM_HAS_HEAP_TLSF (1) // ROM has the implementation of the tlsf and multi-heap library
#define ESP_ROM_TLSF_CHECK_PATCH (1) // ROM does not contain the patch of tlsf_check_pool()
#define ESP_ROM_MULTI_HEAP_WALK_PATCH (1) // ROM does not contain the patch of multi_heap_walk()
#define ESP_ROM_HAS_LAYOUT_TABLE (1) // ROM has the layout table
#define ESP_ROM_HAS_SPI_FLASH (1) // ROM has the implementation of SPI Flash driver
#define ESP_ROM_HAS_REGI2C_BUG (1) // ROM has the regi2c bug

Wyświetl plik

@ -43,6 +43,10 @@ config ESP_ROM_TLSF_CHECK_PATCH
bool
default y
config ESP_ROM_MULTI_HEAP_WALK_PATCH
bool
default y
config ESP_ROM_HAS_LAYOUT_TABLE
bool
default y

Wyświetl plik

@ -16,6 +16,7 @@
#define ESP_ROM_HAS_HAL_SYSTIMER (1) // ROM has the implementation of Systimer HAL driver
#define ESP_ROM_HAS_HEAP_TLSF (1) // ROM has the implementation of the tlsf and multi-heap library
#define ESP_ROM_TLSF_CHECK_PATCH (1) // ROM does not contain the patch of tlsf_check_pool()
#define ESP_ROM_MULTI_HEAP_WALK_PATCH (1) // ROM does not contain the patch of multi_heap_walk()
#define ESP_ROM_HAS_LAYOUT_TABLE (1) // ROM has the layout table
#define ESP_ROM_HAS_SPI_FLASH (1) // ROM has the implementation of SPI Flash driver
#define ESP_ROM_WITHOUT_REGI2C (1) // ROM has no regi2c APIs

Wyświetl plik

@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @brief Opaque handle to a registered heap */
typedef struct multi_heap_info *multi_heap_handle_t;
/**
* @brief Callback called when walking the given heap blocks of memory
*
* @param block_ptr Pointer to the block data
* @param block_size The size of the block
* @param block_used Block status. 0: free, 1: allocated
* @param user_data Opaque pointer to user defined data
*
* @return True if the walker is expected to continue the heap traversal
* False if the walker is expected to stop the traversal of the heap
*/
typedef bool (*multi_heap_walker_cb_t)(void *block_ptr, size_t block_size, int block_used, void *user_data);
/**
* @brief Call the tlsf_walk_pool function of the heap given as parameter with
* the walker function passed as parameter
*
* @param heap The heap to traverse
* @param walker_func The walker to trigger on each block of the heap
* @param user_data Opaque pointer to user defined data
*/
void multi_heap_walk(multi_heap_handle_t heap, multi_heap_walker_cb_t walker_func, void *user_data);
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -0,0 +1,50 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*
* This file is a patch for the multi_heap.c file stored in ROM
* - added function multi_heap_walk
*/
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include "esp_rom_multi_heap.h"
// Hook to force the linker to include this file
void esp_rom_include_multi_heap_patch(void)
{
}
/*!
* @brief Opaque types for TLSF implementation
*/
typedef void* tlsf_t;
typedef void* pool_t;
typedef void* tlsf_walker;
typedef struct multi_heap_info {
void *lock;
size_t free_bytes;
size_t minimum_free_bytes;
size_t pool_size;
void* heap_data;
} heap_t;
extern void tlsf_walk_pool(pool_t pool, tlsf_walker walker, void* user);
extern pool_t tlsf_get_pool(tlsf_t tlsf);
extern void multi_heap_internal_lock(multi_heap_handle_t heap);
extern void multi_heap_internal_unlock(multi_heap_handle_t heap);
void multi_heap_walk(multi_heap_handle_t heap, multi_heap_walker_cb_t walker_func, void *user_data)
{
assert(heap != NULL);
multi_heap_internal_lock(heap);
tlsf_walk_pool(tlsf_get_pool(heap->heap_data), walker_func, user_data);
multi_heap_internal_unlock(heap);
}

Wyświetl plik

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -15,6 +15,7 @@
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include "esp_rom_caps.h"
#include "esp_rom_tlsf.h"
@ -24,13 +25,17 @@
*/
typedef void* tlsf_t;
typedef void* pool_t;
typedef void* tlsf_walker;
typedef ptrdiff_t tlsfptr_t;
/* ----------------------------------------------------------------
* Bring certain inline functions, macro and structures from the
* tlsf ROM implementation to be able to compile the patch.
* ---------------------------------------------------------------- */
#if !defined (tlsf_assert)
#define tlsf_assert assert
#endif
#define tlsf_cast(t, exp) ((t) (exp))
#define block_header_free_bit (1 << 0)
@ -72,6 +77,30 @@ static inline __attribute__((always_inline)) block_header_t* block_from_ptr(cons
tlsf_cast(unsigned char*, ptr) - block_start_offset);
}
static inline __attribute__((always_inline)) block_header_t* offset_to_block(const void* ptr, size_t size)
{
return tlsf_cast(block_header_t*, tlsf_cast(tlsfptr_t, ptr) + size);
}
static inline __attribute__((always_inline)) int block_is_last(const block_header_t* block)
{
return block_size(block) == 0;
}
static inline __attribute__((always_inline)) void* block_to_ptr(const block_header_t* block)
{
return tlsf_cast(void*,
tlsf_cast(unsigned char*, block) + block_start_offset);
}
static inline __attribute__((always_inline)) block_header_t* block_next(const block_header_t* block)
{
block_header_t* next = offset_to_block(block_to_ptr(block),
block_size(block) - block_header_overhead);
tlsf_assert(!block_is_last(block));
return next;
}
/* ----------------------------------------------------------------
* End of the environment necessary to compile and link the patch
* defined below
@ -92,7 +121,9 @@ typedef struct integrity_t
int status;
} integrity_t;
static void integrity_walker(void* ptr, size_t size, int used, void* user)
typedef bool (*tlsf_walker)(void* ptr, size_t size, int used, void* user);
static bool integrity_walker(void* ptr, size_t size, int used, void* user)
{
block_header_t* block = block_from_ptr(ptr);
integrity_t* integ = tlsf_cast(integrity_t*, user);
@ -124,9 +155,38 @@ static void integrity_walker(void* ptr, size_t size, int used, void* user)
integ->prev_status = this_status;
integ->status += status;
return true;
}
static bool default_walker(void* ptr, size_t size, int used, void* user)
{
(void)user;
printf("\t%p %s size: %x (%p)\n", ptr, used ? "used" : "free", (unsigned int)size, block_from_ptr(ptr));
return true;
}
void tlsf_walk_pool(pool_t pool, tlsf_walker walker, void* user)
{
tlsf_walker pool_walker = walker ? walker : default_walker;
block_header_t* block =
offset_to_block(pool, -(int)block_header_overhead);
bool ret_val = true;
while (block && !block_is_last(block) && ret_val == true)
{
ret_val = pool_walker(
block_to_ptr(block),
block_size(block),
!block_is_free(block),
user);
if (ret_val == true) {
block = block_next(block);
}
}
}
extern void tlsf_walk_pool(pool_t pool, tlsf_walker walker, void* user);
int tlsf_check_pool(pool_t pool)
{
/* Check that the blocks are physically correct. */

Wyświetl plik

@ -119,15 +119,6 @@ menu "Heap memory debugging"
features will be added and bugs will be fixed in the IDF source
but cannot be synced to ROM.
config HEAP_TLSF_CHECK_PATCH
bool "Patch the tlsf_check_pool() for ROM HEAP TLSF implementation"
depends on HEAP_TLSF_USE_ROM_IMPL && IDF_TARGET_ESP32C2 && ESP32C2_REV_MIN_FULL < 200
default y
help
ROM does not contain the patch of tlsf_check_pool() allowing perform
the integrity checking on used blocks. The patch to allow such check
needs to be applied.
config HEAP_PLACE_FUNCTION_INTO_FLASH
bool "Force the entire heap component to be placed in flash memory"
depends on !HEAP_TLSF_USE_ROM_IMPL

Wyświetl plik

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -15,6 +15,10 @@
#include "heap_private.h"
#include "esp_system.h"
#if CONFIG_HEAP_TLSF_USE_ROM_IMPL
#include "esp_rom_multi_heap.h"
#endif
#ifdef CONFIG_HEAP_USE_HOOKS
#define CALL_HOOK(hook, ...) { \
if (hook != NULL) { \
@ -860,3 +864,46 @@ void *heap_caps_aligned_calloc(size_t alignment, size_t n, size_t size, uint32_t
return ptr;
}
typedef struct walker_data {
void *opaque_ptr;
heap_caps_walker_cb_t cb_func;
heap_t *heap;
} walker_data_t;
__attribute__((noinline)) static bool heap_caps_walker(void* block_ptr, size_t block_size, int block_used, void *user_data)
{
walker_data_t *walker_data = (walker_data_t*)user_data;
walker_heap_into_t heap_info = {
(intptr_t)walker_data->heap->start,
(intptr_t)walker_data->heap->end
};
walker_block_info_t block_info = {
block_ptr,
block_size,
(bool)block_used
};
return walker_data->cb_func(heap_info, block_info, walker_data->opaque_ptr);
}
void heap_caps_walk(uint32_t caps, heap_caps_walker_cb_t walker_func, void *user_data)
{
assert(walker_func != NULL);
bool all_heaps = caps & MALLOC_CAP_INVALID;
heap_t *heap;
SLIST_FOREACH(heap, &registered_heaps, next) {
if (heap->heap != NULL
&& (all_heaps || (get_all_caps(heap) & caps) == caps)) {
walker_data_t walker_data = {user_data, walker_func, heap};
multi_heap_walk(heap->heap, heap_caps_walker, &walker_data);
}
}
}
void heap_caps_walk_all(heap_caps_walker_cb_t walker_func, void *user_data)
{
heap_caps_walk(MALLOC_CAP_INVALID, walker_func, user_data);
}

Wyświetl plik

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2019-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -444,6 +444,56 @@ void heap_caps_dump_all(void);
*/
size_t heap_caps_get_allocated_size( void *ptr );
/**
* @brief Structure used to store heap related data passed to
* the walker callback function
*/
typedef struct walker_heap_info {
intptr_t start; ///< Start address of the heap in which the block is located
intptr_t end; ///< End address of the heap in which the block is located
} walker_heap_into_t;
/**
* @brief Structure used to store block related data passed to
* the walker callback function
*/
typedef struct walker_block_info {
void *ptr; ///< Pointer to the block data
size_t size; ///< The size of the block
bool used; ///< Block status. True: used, False: free
} walker_block_info_t;
/**
* @brief Function callback used to get information of memory block
* during calls to heap_caps_walk or heap_caps_walk_all
*
* @param heap_info See walker_heap_into_t
* @param block_info See walker_block_info_t
* @param user_data Opaque pointer to user defined data
*
* @return True to proceed with the heap traversal
* False to stop the traversal of the current heap and continue
* with the traversal of the next heap (if any)
*/
typedef bool (*heap_caps_walker_cb_t)(walker_heap_into_t heap_info, walker_block_info_t block_info, void *user_data);
/**
* @brief Function called to walk through the heaps with the given set of capabilities
*
* @param caps The set of capabilities assigned to the heaps to walk through
* @param walker_func Callback called for each block of the heaps being traversed
* @param user_data Opaque pointer to user defined data
*/
void heap_caps_walk(uint32_t caps, heap_caps_walker_cb_t walker_func, void *user_data);
/**
* @brief Function called to walk through all heaps defined by the heap component
*
* @param walker_func Callback called for each block of the heaps being traversed
* @param user_data Opaque pointer to user defined data
*/
void heap_caps_walk_all(heap_caps_walker_cb_t walker_func, void *user_data);
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -207,6 +207,29 @@ size_t multi_heap_reset_minimum_free_bytes(multi_heap_handle_t heap);
*/
void multi_heap_restore_minimum_free_bytes(multi_heap_handle_t heap, const size_t new_minimum_free_bytes_value);
/**
* @brief Callback called when walking the given heap blocks of memory
*
* @param block_ptr Pointer to the block data
* @param block_size The size of the block
* @param block_used Block status. 0: free, 1: allocated
* @param user_data Opaque pointer to user defined data
*
* @return True if the walker is expected to continue the heap traversal
* False if the walker is expected to stop the traversal of the heap
*/
typedef bool (*multi_heap_walker_cb_t)(void *block_ptr, size_t block_size, int block_used, void *user_data);
/**
* @brief Call the tlsf_walk_pool function of the heap given as parameter with
* the walker function passed as parameter
*
* @param heap The heap to traverse
* @param walker_func The walker to trigger on each block of the heap
* @param user_data Opaque pointer to user defined data
*/
void multi_heap_walk(multi_heap_handle_t heap, multi_heap_walker_cb_t walker_func, void *user_data);
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -355,13 +355,11 @@ bool multi_heap_check(multi_heap_handle_t heap, bool print_errors)
return valid;
}
__attribute__((noinline)) static void multi_heap_dump_tlsf(void* ptr, size_t size, int used, void* user)
__attribute__((noinline)) static bool 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",
(void *)ptr,
size,
used ? "No" : "Yes");
MULTI_HEAP_STDERR_PRINTF("Block %p data, size: %d bytes, Free: %s \n", (void *)ptr, size, used ? "No" : "Yes");
return true;
}
void multi_heap_dump(multi_heap_handle_t heap)
@ -392,7 +390,7 @@ size_t multi_heap_minimum_free_size_impl(multi_heap_handle_t heap)
return heap->minimum_free_bytes;
}
__attribute__((noinline)) static void multi_heap_get_info_tlsf(void* ptr, size_t size, int used, void* user)
__attribute__((noinline)) static bool multi_heap_get_info_tlsf(void* ptr, size_t size, int used, void* user)
{
multi_heap_info_t *info = user;
@ -407,6 +405,7 @@ __attribute__((noinline)) static void multi_heap_get_info_tlsf(void* ptr, size_t
}
info->total_blocks++;
return true;
}
void multi_heap_get_info_impl(multi_heap_handle_t heap, multi_heap_info_t *info)
@ -431,6 +430,15 @@ void multi_heap_get_info_impl(multi_heap_handle_t heap, multi_heap_info_t *info)
multi_heap_internal_unlock(heap);
}
void multi_heap_walk(multi_heap_handle_t heap, multi_heap_walker_cb_t walker_func, void *user_data)
{
assert(heap != NULL);
multi_heap_internal_lock(heap);
tlsf_walk_pool(tlsf_get_pool(heap->heap_data), walker_func, user_data);
multi_heap_internal_unlock(heap);
}
#endif // CONFIG_HEAP_TLSF_USE_ROM_IMPL
size_t multi_heap_reset_minimum_free_bytes(multi_heap_handle_t heap)

Wyświetl plik

@ -8,7 +8,8 @@ set(src_test "test_heap_main.c"
"test_malloc.c"
"test_realloc.c"
"test_runtime_heap_reg.c"
"test_task_tracking.c")
"test_task_tracking.c"
"test_walker.c")
idf_component_register(SRCS ${src_test}
INCLUDE_DIRS "."

Wyświetl plik

@ -0,0 +1,101 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "unity.h"
#include "stdio.h"
#include "esp_heap_caps.h"
#include "esp_rom_sys.h"
#define PASS_CODE 0x9876BAAB
#define ALLOC_SIZE 16
static void calculate_block_metadata_size(size_t *header, size_t *footer)
{
*header = 0;
*footer = 0;
#if !CONFIG_HEAP_POISONING_DISABLED
*header += 8; // sizeof(poison_head_t)
*footer += 4; // sizeof(poison_tail_t)
#endif
#if CONFIG_HEAP_TASK_TRACKING
*header += 4; // sizeof(TaskHandle_t)
#endif
}
static bool block_found = false;
static bool heap_corrupted = false;
static bool heap_walker(walker_heap_into_t heap_info, walker_block_info_t block_info, void* user_data)
{
if ((intptr_t)heap_info.end - (intptr_t)block_info.ptr < block_info.size)
{
heap_corrupted = true;
return false;
}
TEST_ASSERT(*(uint32_t*)user_data == PASS_CODE);
TEST_ASSERT_NOT_NULL(block_info.ptr);
size_t metadata_size_head = 0;
size_t metadata_size_tail = 0;
calculate_block_metadata_size(&metadata_size_head, &metadata_size_tail);
/* look for the first 4 bytes pass code to identify the memory allocated in the test */
const uint32_t pass_code = *((uint32_t*)block_info.ptr + (metadata_size_head / sizeof(uint32_t)));
if (pass_code == PASS_CODE) {
TEST_ASSERT(block_info.size == ALLOC_SIZE + metadata_size_head + metadata_size_tail);
TEST_ASSERT_TRUE(block_info.used);
block_found = true;
}
return true;
}
/* This test assures the proper functioning of heap_caps_walk and heap_caps_walk_all
* when a corruption occurs in a random heap. The callback which detects the corruption
* returns false to the walker which should result in the interruption of the heap traversal
* by the walker instead of a crash.
*/
TEST_CASE("heap walker", "[heap]")
{
/* Allocate memory using the MALLOC_CAP_DEFAULT capability */
void *default_ptr = heap_caps_malloc(ALLOC_SIZE, MALLOC_CAP_DEFAULT);
TEST_ASSERT_NOT_NULL(default_ptr);
/* Write the pass code in the first word of the allocated memory */
*((uint32_t*)default_ptr) = (uint32_t)PASS_CODE;
/* call the heap_caps_walker to make sure the hook function is triggered
* and check that the allocated memory is found while walking the heap */
uint32_t user_code = PASS_CODE;
heap_caps_walk_all(heap_walker, &user_code);
TEST_ASSERT_TRUE(block_found);
}
/* This test assures the proper functioning of heap_caps_walk and heap_caps_walk_all
*/
TEST_CASE("heap walker corrupted heap detection", "[heap]")
{
/* Allocate memory using the MALLOC_CAP_DEFAULT capability */
void *default_ptr = heap_caps_malloc(ALLOC_SIZE, MALLOC_CAP_DEFAULT);
TEST_ASSERT_NOT_NULL(default_ptr);
size_t metadata_size_head = 0;
size_t metadata_size_tail = 0;
calculate_block_metadata_size(&metadata_size_head, &metadata_size_tail);
(void)metadata_size_tail;
/* corrupting the size field of the block metadata with a size bigger
* than the heap itself */
*((uint32_t*)default_ptr - (metadata_size_head / 4) - 1) = 0xFF000000;
/* Write the pass code in the first word of the allocated memory */
*((uint32_t*)default_ptr) = (uint32_t)PASS_CODE;
/* call the heap_caps_walker to make sure the hook function is triggered
* and check that the allocated memory is found while walking the heap */
uint32_t user_code = PASS_CODE;
heap_caps_walk_all(heap_walker, &user_code);
TEST_ASSERT_TRUE(heap_corrupted);
}

@ -1 +1 @@
Subproject commit d2e28f872472ffc6a704faae65ddee1f24e2dfba
Subproject commit 8fc595fe223cd0b3b5d7b29eb86825e4bd38e6e8