ITADN

Collision between newlib aclocator and mbed allocator wrappers when MBED_HEAP_STATS_ENABLED is enabled

#552OpenJohnK1987 创建于 2026-03-06
J
JohnK1987commented
***Issue*** In _mbed_alloc_wrappers.cpp_, `__real__memalign_r` from newlib and this one internally calls `_malloc_r`, which is redirected to `__wrap__malloc_r`. When MbedStats are enabled, **malloc_wrapper()** add `alloc_info_t` and returns a shifted pointer. The `__real__memalign_r` expects a raw allocator pointer, so then reads invalid metadata, and can crash with BusFault. That issue causes system crash durring GT test **mbed-usb-device-msd**. It can probably occurs on any target with DCACHE and MBED_ALL_STATS_ENABLED (that enable also MBED_HEAP_STATS_ENABLED). **Proposed change** of __wrap__memalign_r and free_wrapper functions. The `__wrap__memalign_r` will not call `__real__memalign_r` but directly calls `__real__malloc_r` with extra space, manually computes aligned pointerm, writes its own memalign-aware header and returns aligned pointer. ``` c++ #if MBED_HEAP_STATS_ENABLED // Two signatures distinguish regular malloc allocations from memalign allocations in free_wrapper #define MBED_HEAP_STATS_SIGNATURE (0xdeadbeef) #define MBED_HEAP_STATS_MEMALIGN_SIGNATURE (MBED_HEAP_STATS_SIGNATURE +1) extern "C" void free_wrapper(struct _reent *r, void *ptr, void *caller) { #if MBED_MEM_TRACING_ENABLED mbed_mem_trace_lock(); #endif #if MBED_HEAP_STATS_ENABLED malloc_stats_mutex->lock(); alloc_info_t *alloc_info = NULL; if (ptr != NULL) { alloc_info = ((alloc_info_t *)ptr) - 1; if (MBED_HEAP_STATS_SIGNATURE == alloc_info->signature || MBED_HEAP_STATS_MEMALIGN_SIGNATURE == alloc_info->signature) { // For memalign allocations the raw base pointer is stashed in the // word immediately before alloc_info; for regular malloc allocations // alloc_info itself is the base. void *ptr_to_free = (MBED_HEAP_STATS_MEMALIGN_SIGNATURE == alloc_info->signature) ? ((void **)alloc_info)[-1] : (void *)alloc_info; size_t user_size = alloc_info->size; size_t alloc_size = get_malloc_block_total_size(ptr_to_free); alloc_info->signature = 0x0; heap_stats.current_size -= user_size; heap_stats.alloc_cnt -= 1; heap_stats.overhead_size -= (alloc_size - user_size); __real__free_r(r, ptr_to_free); } else { __real__free_r(r, ptr); } } malloc_stats_mutex->unlock(); #else // #if MBED_HEAP_STATS_ENABLED __real__free_r(r, ptr); #endif // #if MBED_HEAP_STATS_ENABLED #if MBED_MEM_TRACING_ENABLED mbed_mem_trace_free(ptr, caller); mbed_mem_trace_unlock(); #endif // #if MBED_MEM_TRACING_ENABLED } extern "C" void *__wrap__memalign_r(struct _reent *r, size_t alignment, size_t bytes) { void *ptr = NULL; #if MBED_MEM_TRACING_ENABLED mbed_mem_trace_lock(); #endif #if MBED_HEAP_STATS_ENABLED // Header before aligned ptr: [void *raw_base] [alloc_info_t] const size_t hdr = sizeof(void *) + sizeof(alloc_info_t); size_t pad = (alignment > hdr) ? alignment : hdr; void *raw = NULL; if (bytes <= SIZE_MAX - pad) { raw = __real__malloc_r(r, bytes + pad); } if (raw != NULL) { uintptr_t min_user = (uintptr_t)raw + hdr; uintptr_t user_addr = (min_user + alignment - 1u) & ~(uintptr_t)(alignment - 1u); alloc_info_t *info = ((alloc_info_t *)user_addr) - 1; info->size = bytes; info->signature = MBED_HEAP_STATS_MEMALIGN_SIGNATURE; ((void **)info)[-1] = raw; // stash raw base for free_wrapper ptr = (void *)user_addr; malloc_stats_mutex->lock(); heap_stats.current_size += bytes; heap_stats.total_size += bytes; heap_stats.alloc_cnt += 1; if (heap_stats.current_size > heap_stats.max_size) { heap_stats.max_size = heap_stats.current_size; } heap_stats.overhead_size += get_malloc_block_total_size(raw) - bytes; malloc_stats_mutex->unlock(); } else { malloc_stats_mutex->lock(); heap_stats.alloc_fail_cnt += 1; malloc_stats_mutex->unlock(); } #else // #if MBED_HEAP_STATS_ENABLED ptr = __real__memalign_r(r, alignment, bytes); #endif // #if MBED_HEAP_STATS_ENABLED #if MBED_MEM_TRACING_ENABLED mbed_mem_trace_malloc(ptr, bytes, MBED_CALLER_ADDR()); mbed_mem_trace_unlock(); #endif // #if MBED_MEM_TRACING_ENABLED return ptr; } ```
1 条评论