From 3fa818c78f28239eb0c309c684c52c22f9f0bb40 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 8 Jun 2026 09:52:45 +0200 Subject: [PATCH] MINOR: memprof: be careful to account allocations only once For certain calls like strdup(), certain libc call the malloc() symbol themselves, resulting in both strdup() and malloc() accounting for the allocation while a single free() call is accounted for. Usually it's not very hard to spot as these allocations are done inside libc, but yet they complicate the tracing of allocations. Let's note when we enter a handler and refrain from doing the accounting again in this case. This way, the strdup() call place will be accountable for the allocation and the libc's internal malloc() will not be seen. --- src/activity.c | 51 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/src/activity.c b/src/activity.c index 7ce9e76e3..37842af9e 100644 --- a/src/activity.c +++ b/src/activity.c @@ -81,6 +81,7 @@ struct memprof_stats memprof_stats[MEMPROF_HASH_BUCKETS + 1] = { }; /* used to detect recursive calls */ #define MEMPROF_IN_INIT (1U << 0) +#define MEMPROF_IN_HANDLER (1U << 1) static THREAD_LOCAL uint in_memprof = 0; // arithmetic OR of MEMPROF_IN_* @@ -346,11 +347,13 @@ void *malloc(size_t size) struct memprof_stats *bin; void *ret; - if (likely(!(profiling & HA_PROF_MEMORY))) + if (likely(!(profiling & HA_PROF_MEMORY) || (in_memprof & MEMPROF_IN_HANDLER))) return memprof_malloc_handler(size); + in_memprof |= MEMPROF_IN_HANDLER; ret = memprof_malloc_handler(size); size = malloc_usable_size(ret) + sizeof(void *); + in_memprof &= ~MEMPROF_IN_HANDLER; bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_MALLOC); if (unlikely(th_ctx->lock_level & 0x7F)) @@ -373,11 +376,13 @@ void *calloc(size_t nmemb, size_t size) struct memprof_stats *bin; void *ret; - if (likely(!(profiling & HA_PROF_MEMORY))) + if (likely(!(profiling & HA_PROF_MEMORY) || (in_memprof & MEMPROF_IN_HANDLER))) return memprof_calloc_handler(nmemb, size); + in_memprof |= MEMPROF_IN_HANDLER; ret = memprof_calloc_handler(nmemb, size); size = malloc_usable_size(ret) + sizeof(void *); + in_memprof &= ~MEMPROF_IN_HANDLER; bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_CALLOC); if (unlikely(th_ctx->lock_level & 0x7F)) @@ -403,12 +408,14 @@ void *realloc(void *ptr, size_t size) size_t size_before; void *ret; - if (likely(!(profiling & HA_PROF_MEMORY))) + if (likely(!(profiling & HA_PROF_MEMORY) || (in_memprof & MEMPROF_IN_HANDLER))) return memprof_realloc_handler(ptr, size); + in_memprof |= MEMPROF_IN_HANDLER; size_before = malloc_usable_size(ptr); ret = memprof_realloc_handler(ptr, size); size = malloc_usable_size(ret); + in_memprof &= ~MEMPROF_IN_HANDLER; /* only count the extra link for new allocations */ if (!ptr) @@ -441,11 +448,13 @@ char *strdup(const char *s) size_t size; char *ret; - if (likely(!(profiling & HA_PROF_MEMORY))) + if (likely(!(profiling & HA_PROF_MEMORY) || (in_memprof & MEMPROF_IN_HANDLER))) return memprof_strdup_handler(s); + in_memprof |= MEMPROF_IN_HANDLER; ret = memprof_strdup_handler(s); size = malloc_usable_size(ret) + sizeof(void *); + in_memprof &= ~MEMPROF_IN_HANDLER; bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_STRDUP); if (unlikely(th_ctx->lock_level & 0x7F)) @@ -471,13 +480,15 @@ void free(void *ptr) struct memprof_stats *bin; size_t size_before; - if (likely(!(profiling & HA_PROF_MEMORY) || !ptr)) { + if (likely(!(profiling & HA_PROF_MEMORY) || !ptr || (in_memprof & MEMPROF_IN_HANDLER))) { memprof_free_handler(ptr); return; } + in_memprof |= MEMPROF_IN_HANDLER; size_before = malloc_usable_size(ptr) + sizeof(void *); memprof_free_handler(ptr); + in_memprof &= ~MEMPROF_IN_HANDLER; bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_FREE); if (unlikely(th_ctx->lock_level & 0x7F)) @@ -497,10 +508,13 @@ char *strndup(const char *s, size_t size) return NULL; ret = memprof_strndup_handler(s, size); - if (likely(!(profiling & HA_PROF_MEMORY))) + if (likely(!(profiling & HA_PROF_MEMORY) || (in_memprof & MEMPROF_IN_HANDLER))) return ret; + in_memprof |= MEMPROF_IN_HANDLER; size = malloc_usable_size(ret) + sizeof(void *); + in_memprof &= ~MEMPROF_IN_HANDLER; + bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_STRNDUP); if (unlikely(th_ctx->lock_level & 0x7F)) _HA_ATOMIC_ADD(&bin->locked_calls, 1); @@ -518,10 +532,13 @@ void *valloc(size_t size) return NULL; ret = memprof_valloc_handler(size); - if (likely(!(profiling & HA_PROF_MEMORY))) + if (likely(!(profiling & HA_PROF_MEMORY) || (in_memprof & MEMPROF_IN_HANDLER))) return ret; + in_memprof |= MEMPROF_IN_HANDLER; size = malloc_usable_size(ret) + sizeof(void *); + in_memprof &= ~MEMPROF_IN_HANDLER; + bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_VALLOC); if (unlikely(th_ctx->lock_level & 0x7F)) _HA_ATOMIC_ADD(&bin->locked_calls, 1); @@ -539,10 +556,13 @@ void *pvalloc(size_t size) return NULL; ret = memprof_pvalloc_handler(size); - if (likely(!(profiling & HA_PROF_MEMORY))) + if (likely(!(profiling & HA_PROF_MEMORY) || (in_memprof & MEMPROF_IN_HANDLER))) return ret; + in_memprof |= MEMPROF_IN_HANDLER; size = malloc_usable_size(ret) + sizeof(void *); + in_memprof &= ~MEMPROF_IN_HANDLER; + bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_PVALLOC); if (unlikely(th_ctx->lock_level & 0x7F)) _HA_ATOMIC_ADD(&bin->locked_calls, 1); @@ -560,10 +580,13 @@ void *memalign(size_t align, size_t size) return NULL; ret = memprof_memalign_handler(align, size); - if (likely(!(profiling & HA_PROF_MEMORY))) + if (likely(!(profiling & HA_PROF_MEMORY) || (in_memprof & MEMPROF_IN_HANDLER))) return ret; + in_memprof |= MEMPROF_IN_HANDLER; size = malloc_usable_size(ret) + sizeof(void *); + in_memprof &= ~MEMPROF_IN_HANDLER; + bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_MEMALIGN); if (unlikely(th_ctx->lock_level & 0x7F)) _HA_ATOMIC_ADD(&bin->locked_calls, 1); @@ -581,10 +604,13 @@ void *aligned_alloc(size_t align, size_t size) return NULL; ret = memprof_aligned_alloc_handler(align, size); - if (likely(!(profiling & HA_PROF_MEMORY))) + if (likely(!(profiling & HA_PROF_MEMORY) || (in_memprof & MEMPROF_IN_HANDLER))) return ret; + in_memprof |= MEMPROF_IN_HANDLER; size = malloc_usable_size(ret) + sizeof(void *); + in_memprof &= ~MEMPROF_IN_HANDLER; + bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_ALIGNED_ALLOC); if (unlikely(th_ctx->lock_level & 0x7F)) _HA_ATOMIC_ADD(&bin->locked_calls, 1); @@ -602,13 +628,16 @@ int posix_memalign(void **ptr, size_t align, size_t size) return ENOMEM; ret = memprof_posix_memalign_handler(ptr, align, size); - if (likely(!(profiling & HA_PROF_MEMORY))) + if (likely(!(profiling & HA_PROF_MEMORY) || (in_memprof & MEMPROF_IN_HANDLER))) return ret; if (ret != 0) // error return ret; + in_memprof |= MEMPROF_IN_HANDLER; size = malloc_usable_size(*ptr) + sizeof(void *); + in_memprof &= ~MEMPROF_IN_HANDLER; + bin = memprof_get_bin(__builtin_return_address(0), MEMPROF_METH_POSIX_MEMALIGN); if (unlikely(th_ctx->lock_level & 0x7F)) _HA_ATOMIC_ADD(&bin->locked_calls, 1);