[Concept,02/33] malloc: Expose registry-overflow state to tests

Message ID 20260416023021.626949-3-sjg@u-boot.org
State New
Headers
Series Fix memory leaks and test pollution in sandbox tests |

Commit Message

Simon Glass April 16, 2026, 2:29 a.m. UTC
  From: Simon Glass <sjg@chromium.org>

If the mcheck registry ever overflows, later allocations are not
recorded so find_mcheck_hdr_in_chunk() cannot find their headers. Leak
reports then print an empty caller column, and cmd_test_malloc_leak()
fails with a confusing assertion where the expected output shows a
function name and the actual output shows trailing whitespace. The
'registry overflow' printf() that marks this state is printed once and
goes to the silenced test console, which makes the condition hard to
notice.

Promote the one-shot overflow flag to file scope expose it via a new
malloc_mcheck_overflow() function. Check it at the top of
cmd_test_malloc_leak() so any earlier test that exhausts the registry
now produces a direct failure in the leak test rather than a misleading
one based on missing caller strings.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 common/dlmalloc.c        |  5 +++++
 common/mcheck_core.inc.h |  6 +++---
 include/malloc.h         | 16 ++++++++++++++++
 test/cmd/malloc.c        |  6 ++++++
 4 files changed, 30 insertions(+), 3 deletions(-)
  

Patch

diff --git a/common/dlmalloc.c b/common/dlmalloc.c
index f05d7ae83c5..ae1e6d27d08 100644
--- a/common/dlmalloc.c
+++ b/common/dlmalloc.c
@@ -6010,6 +6010,11 @@  bool malloc_backtrace_is_active(bool *skipp, bool *busyp)
 #endif
 }
 
+bool malloc_mcheck_overflow(void)
+{
+	return mcheck_registry_full;
+}
+
 static const char *mcheck_caller(void)
 {
 #if CONFIG_IS_ENABLED(MCHECK_BACKTRACE)
diff --git a/common/mcheck_core.inc.h b/common/mcheck_core.inc.h
index 968b058ba6d..9f13945cde8 100644
--- a/common/mcheck_core.inc.h
+++ b/common/mcheck_core.inc.h
@@ -79,6 +79,7 @@  static char mcheck_pedantic_flag __section(".data") = 0;
 static void *mcheck_registry[REGISTRY_SZ] __section(".data") = {0};
 static size_t mcheck_chunk_count __section(".data") = 0;
 static size_t mcheck_chunk_count_max __section(".data") = 0;
+static bool mcheck_registry_full __section(".data");
 
 typedef unsigned long long mcheck_elem;
 typedef struct {
@@ -200,7 +201,6 @@  static void *mcheck_allocated_helper(void *altoghether_ptr, size_t customer_sz,
 				     size_t alignment, int clean_content,
 				     const char *caller)
 {
-	static bool overflow_msg_shown;
 	const size_t slop = alignment ?
 		mcheck_evaluate_memalign_prefix_size(alignment) - sizeof(struct mcheck_hdr) : 0;
 	struct mcheck_hdr *hdr = (struct mcheck_hdr *)((char *)altoghether_ptr + slop);
@@ -239,8 +239,8 @@  static void *mcheck_allocated_helper(void *altoghether_ptr, size_t customer_sz,
 			return payload; // normal end
 		}
 
-	if (!overflow_msg_shown) {
-		overflow_msg_shown = true;
+	if (!mcheck_registry_full) {
+		mcheck_registry_full = true;
 		printf("\n\nERROR: mcheck registry overflow, pedantic check would be incomplete!\n\n");
 	}
 	return payload;
diff --git a/include/malloc.h b/include/malloc.h
index 05d4c06fb89..0a780fc03c3 100644
--- a/include/malloc.h
+++ b/include/malloc.h
@@ -863,6 +863,22 @@  static inline bool malloc_backtrace_is_active(bool *skipp, bool *busyp)
 }
 #endif
 
+/**
+ * malloc_mcheck_overflow() - Check whether the mcheck registry filled
+ *
+ * The mcheck code registers each allocation's header in a fixed-size array so
+ * that leak reporting and pedantic checking can find it. If the array is ever
+ * exhausted, later allocations are still returned but their caller info cannot
+ * be recovered.
+ *
+ * Return: true if the registry has overflowed at any point
+ */
+#if CONFIG_IS_ENABLED(MCHECK_HEAP_PROTECTION)
+bool malloc_mcheck_overflow(void);
+#else
+static inline bool malloc_mcheck_overflow(void) { return false; }
+#endif
+
 /**
  * malloc_chunk_size() - Return the dlmalloc chunk size for an allocation
  *
diff --git a/test/cmd/malloc.c b/test/cmd/malloc.c
index 95809845dd7..db4350afe68 100644
--- a/test/cmd/malloc.c
+++ b/test/cmd/malloc.c
@@ -63,6 +63,12 @@  static int cmd_test_malloc_leak(struct unit_test_state *uts)
 	void *ptr;
 	int ret;
 
+	/*
+	 * If the mcheck registry ever overflowed, later allocations are not
+	 * registered and leak reports cannot recover the caller string.
+	 */
+	ut_assert(!malloc_mcheck_overflow());
+
 	/* Take a snapshot, then check with no leaks */
 	ut_assertok(malloc_leak_check_start(&snap));
 	ut_assert(snap.count > 0);