mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
heap_caps_calloc_base() calls heap_caps_malloc_base() from the same translation unit (heap_caps_base.c). GNU ld --wrap only redirects undefined references, so that intra-object call binds to the real heap_caps_malloc_base and never enters __wrap_heap_caps_malloc_base. As a result, allocations made through heap_caps_calloc() were never recorded by heap tracing, silently hiding potentially large INTERNAL leaks (e.g. mbedtls SSL buffers via MALLOC_CAP_INTERNAL). Add heap_caps_calloc_base to the --wrap list and implement __wrap_heap_caps_calloc_base, which records the allocation via a noinline trace_calloc helper (mirroring trace_malloc so the recorded call stack depth stays consistent) and calls __real_heap_caps_calloc_base. The inner malloc_base call remains same-TU and unwrapped, so each calloc produces exactly one trace record (no double counting).
151 lines
5.5 KiB
CMake
151 lines
5.5 KiB
CMake
idf_build_get_property(target IDF_TARGET)
|
|
|
|
# On Linux, we only support a few features, hence this simple component registration
|
|
if(${target} STREQUAL "linux")
|
|
idf_component_register(SRCS "heap_caps_linux.c"
|
|
INCLUDE_DIRS "include")
|
|
return()
|
|
endif()
|
|
|
|
set(srcs "heap_caps_base.c"
|
|
"heap_caps.c"
|
|
"heap_caps_init.c"
|
|
"multi_heap.c")
|
|
|
|
# the root dir of TLSF submodule contains headers with static inline
|
|
# functions used in the heap ROM patches. Therefore,
|
|
# the tlsf/ dir must be included in the list of public includes.
|
|
set(includes "include"
|
|
"tlsf")
|
|
|
|
# The TLSF "public" includes should only be used
|
|
# inside the heap component and are therefore added
|
|
# to the list of the private includes from the heap
|
|
# component perspective
|
|
set(priv_includes "private_include"
|
|
"tlsf/include")
|
|
|
|
if(NOT CONFIG_HEAP_TLSF_USE_ROM_IMPL)
|
|
list(APPEND srcs "tlsf/tlsf.c")
|
|
endif()
|
|
|
|
if(NOT CONFIG_HEAP_POISONING_DISABLED)
|
|
list(APPEND srcs "multi_heap_poisoning.c")
|
|
endif()
|
|
|
|
if(CONFIG_HEAP_TASK_TRACKING)
|
|
list(APPEND srcs "heap_task_info.c")
|
|
endif()
|
|
|
|
if(CONFIG_HEAP_TRACING_STANDALONE)
|
|
list(APPEND srcs "heap_trace_standalone.c")
|
|
set_source_files_properties(heap_trace_standalone.c
|
|
PROPERTIES COMPILE_FLAGS
|
|
-Wno-frame-address)
|
|
endif()
|
|
|
|
# Add SoC memory layout to the sources
|
|
|
|
if(NOT BOOTLOADER_BUILD)
|
|
list(APPEND srcs "port/memory_layout_utils.c")
|
|
list(APPEND srcs "port/${target}/memory_layout.c")
|
|
|
|
if(CONFIG_HEAP_TLSF_USE_ROM_IMPL)
|
|
list(APPEND includes "rom_patches/include"
|
|
"rom_patches/${target}")
|
|
|
|
if(CONFIG_ESP_ROM_TLSF_CHECK_PATCH)
|
|
# This file shall be included in the build if TLSF in ROM is activated
|
|
list(APPEND srcs "rom_patches/rom_patch_tlsf.c")
|
|
endif()
|
|
|
|
if(CONFIG_ESP_ROM_MULTI_HEAP_WALK_PATCH)
|
|
# This file shall be included in the build if TLSF in ROM is activated
|
|
list(APPEND srcs "rom_patches/rom_patch_multi_heap.c")
|
|
endif()
|
|
endif()
|
|
endif()
|
|
|
|
set(ldfragments linker.lf)
|
|
|
|
idf_component_register(SRCS "${srcs}"
|
|
INCLUDE_DIRS ${includes}
|
|
PRIV_INCLUDE_DIRS ${priv_includes}
|
|
LDFRAGMENTS ${ldfragments}
|
|
PRIV_REQUIRES soc esp_system)
|
|
|
|
if(CONFIG_HEAP_TLSF_USE_ROM_IMPL AND NOT BOOTLOADER_BUILD)
|
|
# After registering the component, set the tlsf_set_rom_patches symbol as undefined
|
|
# to force the linker to integrate the whole rom_patch_tlsf.c object file inside the
|
|
# final binary. This is necessary because tlsf_set_rom_patches is a constructor, thus,
|
|
# there is no explicit reference/call to it in IDF.
|
|
if(CONFIG_ESP_ROM_TLSF_CHECK_PATCH)
|
|
target_link_libraries(${COMPONENT_LIB} PRIVATE "-u tlsf_set_rom_patches")
|
|
endif()
|
|
|
|
if(CONFIG_ESP_ROM_MULTI_HEAP_WALK_PATCH)
|
|
target_link_libraries(${COMPONENT_LIB} PRIVATE "-u esp_rom_include_multi_heap_patch")
|
|
endif()
|
|
|
|
target_linker_script(${COMPONENT_LIB} INTERFACE "port/${target}/ld/${target}.rom.heap.ld")
|
|
endif()
|
|
|
|
if(CONFIG_HEAP_TRACING)
|
|
set(WRAP_FUNCTIONS
|
|
heap_caps_realloc_base
|
|
heap_caps_malloc_base
|
|
heap_caps_calloc_base
|
|
heap_caps_aligned_alloc_base
|
|
heap_caps_free)
|
|
|
|
foreach(wrap ${WRAP_FUNCTIONS})
|
|
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=${wrap}")
|
|
endforeach()
|
|
endif()
|
|
|
|
if(IDF_BUILD_V2)
|
|
target_compile_options(${COMPONENT_TARGET} PRIVATE "$<$<TARGET_EXISTS:idf::freertos>:-DMULTI_HEAP_FREERTOS>")
|
|
else()
|
|
if(NOT CMAKE_BUILD_EARLY_EXPANSION)
|
|
idf_build_get_property(build_components BUILD_COMPONENTS)
|
|
if(freertos IN_LIST build_components)
|
|
target_compile_options(${COMPONENT_TARGET} PRIVATE "-DMULTI_HEAP_FREERTOS")
|
|
endif()
|
|
endif()
|
|
endif()
|
|
|
|
# KASAN heap integration: hook into alloc/free to maintain shadow memory.
|
|
# heap_kasan.c holds the implementation (compiled without KASAN instrumentation).
|
|
# heap_kasan_hooks.c provides strong (non-weak) overrides of the hook stubs;
|
|
# it intentionally avoids including esp_heap_caps.h to prevent GCC from
|
|
# inheriting the 'weak' attribute from the declarations in that header.
|
|
if(CONFIG_COMPILER_KASAN AND CONFIG_HEAP_USE_HOOKS)
|
|
target_sources(${COMPONENT_LIB} PRIVATE
|
|
"heap_kasan.c"
|
|
"heap_kasan_hooks.c"
|
|
)
|
|
# Sources excluded from KASAN instrumentation:
|
|
# heap_kasan.c / heap_kasan_hooks.c implement the sanitizer hooks themselves
|
|
# (instrumenting them would cause infinite recursion).
|
|
# heap_caps_init.c runs while heap metadata is being brought up: the first
|
|
# allocations happen before the shadow is fully initialised, and the
|
|
# memcpy of the registered-heaps array touches DRAM regions whose
|
|
# shadow state is still being populated.
|
|
set_source_files_properties(
|
|
"heap_caps_init.c"
|
|
"heap_kasan.c"
|
|
"heap_kasan_hooks.c"
|
|
PROPERTIES COMPILE_OPTIONS "-fno-sanitize=kernel-address"
|
|
)
|
|
idf_component_get_property(esp_system_lib esp_system COMPONENT_LIB)
|
|
target_link_libraries(${COMPONENT_LIB} PRIVATE ${esp_system_lib})
|
|
# Force the linker to include our strong hook definitions. Without this,
|
|
# --gc-sections would silently discard them because the call site in
|
|
# heap_caps_base.c uses a weak-symbol pointer (if (hook != NULL) ...) which
|
|
# doesn't create a strong reference that the linker follows.
|
|
target_link_libraries(${COMPONENT_LIB} INTERFACE
|
|
"-u esp_heap_trace_alloc_hook"
|
|
"-u esp_heap_trace_free_hook"
|
|
)
|
|
endif()
|