[Concept,27/35] malloc: Support storing caller information

Message ID 20251210000737.180797-28-sjg@u-boot.org
State New
Headers
Series malloc: Add heap debugging commands and mcheck caller tracking |

Commit Message

Simon Glass Dec. 10, 2025, 12:07 a.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

Add a field to store the caller for each allocation, using the backtrace
information. This can be useful when debugging heap corruption.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---

 common/dlmalloc.c        |  8 ++++----
 common/mcheck_core.inc.h | 28 +++++++++++++++++++++-------
 2 files changed, 25 insertions(+), 11 deletions(-)
  

Patch

diff --git a/common/dlmalloc.c b/common/dlmalloc.c
index e288d94d433..706c12d9b9a 100644
--- a/common/dlmalloc.c
+++ b/common/dlmalloc.c
@@ -5954,7 +5954,7 @@  void *dlmalloc(size_t bytes)
 
 	if (!p)
 		return p;
-	return mcheck_alloc_posthook(p, bytes);
+	return mcheck_alloc_posthook(p, bytes, NULL);
 }
 
 void dlfree(void *mem) { dlfree_impl(mcheck_free_prehook(mem)); }
@@ -5979,7 +5979,7 @@  void *dlrealloc(void *oldmem, size_t bytes)
 	p = dlrealloc_impl(p, newsz);
 	if (!p)
 		return p;
-	return mcheck_alloc_noclean_posthook(p, bytes);
+	return mcheck_alloc_noclean_posthook(p, bytes, NULL);
 }
 
 void *dlmemalign(size_t alignment, size_t bytes)
@@ -5990,7 +5990,7 @@  void *dlmemalign(size_t alignment, size_t bytes)
 
 	if (!p)
 		return p;
-	return mcheck_memalign_posthook(alignment, p, bytes);
+	return mcheck_memalign_posthook(alignment, p, bytes, NULL);
 }
 
 /* dlpvalloc, dlvalloc redirect to dlmemalign, so they need no wrapping */
@@ -6004,7 +6004,7 @@  void *dlcalloc(size_t n, size_t elem_size)
 
 	if (!p)
 		return p;
-	return mcheck_alloc_noclean_posthook(p, n * elem_size);
+	return mcheck_alloc_noclean_posthook(p, n * elem_size, NULL);
 }
 
 /* mcheck API */
diff --git a/common/mcheck_core.inc.h b/common/mcheck_core.inc.h
index c2089add0d6..63dbeaa5f56 100644
--- a/common/mcheck_core.inc.h
+++ b/common/mcheck_core.inc.h
@@ -73,6 +73,7 @@ 
 // Full test suite can exceed 10000 concurrent allocations
 #define REGISTRY_SZ	12000
 #define CANARY_DEPTH	2
+#define MCHECK_CALLER_LEN	48
 
 // avoid problems with BSS at early stage:
 static char mcheck_pedantic_flag __section(".data") = 0;
@@ -88,6 +89,7 @@  struct mcheck_hdr {
 	size_t size; /* Exact size requested by user.  */
 	size_t aln_skip; /* Ignored bytes, before the mcheck_hdr, to fulfill alignment */
 	mcheck_canary canary; /* Magic number to check header integrity.  */
+	char caller[MCHECK_CALLER_LEN]; /* caller info for debugging */
 };
 
 static void mcheck_default_abort(enum mcheck_status status, const void *p)
@@ -196,7 +198,8 @@  static size_t mcheck_alloc_prehook(size_t sz)
 }
 
 static void *mcheck_allocated_helper(void *altoghether_ptr, size_t customer_sz,
-				     size_t alignment, int clean_content)
+				     size_t alignment, int clean_content,
+				     const char *caller)
 {
 	const size_t slop = alignment ?
 		mcheck_evaluate_memalign_prefix_size(alignment) - sizeof(struct mcheck_hdr) : 0;
@@ -207,6 +210,10 @@  static void *mcheck_allocated_helper(void *altoghether_ptr, size_t customer_sz,
 	hdr->aln_skip = slop;
 	for (i = 0; i < CANARY_DEPTH; ++i)
 		hdr->canary.elems[i] = MAGICWORD;
+	if (caller)
+		strlcpy(hdr->caller, caller, MCHECK_CALLER_LEN);
+	else
+		hdr->caller[0] = '\0';
 
 	char *payload = (char *)&hdr[1];
 
@@ -239,14 +246,19 @@  static void *mcheck_allocated_helper(void *altoghether_ptr, size_t customer_sz,
 	return payload;
 }
 
-static void *mcheck_alloc_posthook(void *altoghether_ptr, size_t customer_sz)
+static void *mcheck_alloc_posthook(void *altoghether_ptr, size_t customer_sz,
+				   const char *caller)
 {
-	return mcheck_allocated_helper(altoghether_ptr, customer_sz, ANY_ALIGNMENT, CLEAN_CONTENT);
+	return mcheck_allocated_helper(altoghether_ptr, customer_sz,
+				       ANY_ALIGNMENT, CLEAN_CONTENT, caller);
 }
 
-static void *mcheck_alloc_noclean_posthook(void *altoghether_ptr, size_t customer_sz)
+static void *mcheck_alloc_noclean_posthook(void *altoghether_ptr,
+					   size_t customer_sz,
+					   const char *caller)
 {
-	return mcheck_allocated_helper(altoghether_ptr, customer_sz, ANY_ALIGNMENT, KEEP_CONTENT);
+	return mcheck_allocated_helper(altoghether_ptr, customer_sz,
+				       ANY_ALIGNMENT, KEEP_CONTENT, caller);
 }
 
 static size_t mcheck_memalign_prehook(size_t alig, size_t sz)
@@ -254,9 +266,11 @@  static size_t mcheck_memalign_prehook(size_t alig, size_t sz)
 	return mcheck_evaluate_memalign_prefix_size(alig) + sz + sizeof(mcheck_canary);
 }
 
-static void *mcheck_memalign_posthook(size_t alignment, void *altoghether_ptr, size_t customer_sz)
+static void *mcheck_memalign_posthook(size_t alignment, void *altoghether_ptr,
+				      size_t customer_sz, const char *caller)
 {
-	return mcheck_allocated_helper(altoghether_ptr, customer_sz, alignment, CLEAN_CONTENT);
+	return mcheck_allocated_helper(altoghether_ptr, customer_sz, alignment,
+				       CLEAN_CONTENT, caller);
 }
 
 static enum mcheck_status mcheck_mprobe(void *ptr)