[Concept,07/17] test: Show leaked allocations with ut -L

Message ID 20260316183050.3855921-8-sjg@u-boot.org
State New
Headers
Series Add automatic memory-leak detection to U-Boot tests |

Commit Message

Simon Glass March 16, 2026, 6:30 p.m. UTC
  From: Simon Glass <sjg@chromium.org>

Use the new malloc_leak_check functions to show the address, size
and caller backtrace of each leaked allocation, rather than just the
total byte count.

Example output:

  Test: acpi_bgrt: acpi.c
  Leak: 2 allocs
    14a5c5c0 110 stdio_clone:230 <-stdio_register_dev:244
    14a5c6d0  b0 map_to_sysmem:210 <-video_post_probe:823

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

 doc/develop/malloc.rst | 30 +++++++++++++++++-------------
 test/test-main.c       | 21 +++++++++++----------
 2 files changed, 28 insertions(+), 23 deletions(-)
  

Patch

diff --git a/doc/develop/malloc.rst b/doc/develop/malloc.rst
index 74acc3220af..6bb17dca7b1 100644
--- a/doc/develop/malloc.rst
+++ b/doc/develop/malloc.rst
@@ -503,14 +503,21 @@  by checking ``malloc_get_info()`` before and after::
 **Automatic leak checking with ut -L**
 
 The ``ut`` command accepts a ``-L`` flag that checks for memory leaks around
-each test. It takes a ``mallinfo()`` snapshot at the start of ``ut_run_test()``
-and compares it at the end, after both ``test_pre_run()`` and
-``test_post_run()`` have completed::
+each test. It snapshots every in-use heap chunk at the start of
+``ut_run_test()`` and compares after both ``test_pre_run()`` and
+``test_post_run()`` have completed. Any new allocations are reported with
+their address, size and caller backtrace::
 
-    => ut -L dm dm_test_acpi_bgrt
+    => ut -LE dm dm_test_acpi_bgrt
     Test: acpi_bgrt: acpi.c
-    Leak: 448 bytes: acpi_bgrt
-    ...
+    Leak: 2 allocs
+      14a5c5c0 110 stdio_clone:230 <-stdio_register_dev:244 <-vidconsole_post_probe:961
+      14a5c6d0  b0 map_to_sysmem:210 <-video_post_probe:823 <-device_probe:589
+    Result: PASS: acpi_bgrt: acpi.c
+
+The snapshot is stored using ``os_malloc()`` so it does not affect the
+heap being measured. Caller backtraces are available when
+``CONFIG_MCHECK_HEAP_PROTECTION`` is enabled (the default for sandbox).
 
 When using uman, pass ``--leak-check``::
 
@@ -523,13 +530,10 @@  This makes it easy to scan an entire test suite for leaks::
 **Practical workflow**
 
 1. Run ``um t --leak-check -V dm`` (or another suite) to find leaky tests
-2. When a leak is detected, add ``malloc_dump_to_file()`` calls before and
-   after the leaking operation
-3. Run the test and compare the dump files to identify leaked allocations
-4. Use the caller backtrace in the dump to find the allocation site
-5. If more detail is needed, enable ``malloc_log_start()`` to trace all
-   allocations during the operation
-6. Fix the leak and verify the test passes
+2. Use the caller backtrace in the ``-L`` output to find the allocation site
+3. If more detail is needed, add ``malloc_dump_to_file()`` calls or enable
+   ``malloc_log_start()`` to trace all allocations during the operation
+4. Fix the leak and verify the test passes
 
 **Dumping heap state on exit**
 
diff --git a/test/test-main.c b/test/test-main.c
index be13084ed92..09458fa91da 100644
--- a/test/test-main.c
+++ b/test/test-main.c
@@ -631,7 +631,7 @@  static int ut_run_test(struct unit_test_state *uts, struct unit_test *test,
 {
 	const char *fname = strrchr(test->file, '/') + 1;
 	const char *note = "";
-	struct mallinfo leak_before;
+	struct malloc_leak_snap leak_snap = {};
 	int old_fail_count;
 	int ret;
 
@@ -640,7 +640,7 @@  static int ut_run_test(struct unit_test_state *uts, struct unit_test *test,
 	printf("Test: %s: %s%s\n", test_name, fname, note);
 
 	if (uts->leak_check)
-		leak_before = mallinfo();
+		malloc_leak_check_start(&leak_snap);
 
 	/* Allow access to test state from drivers */
 	ut_set_state(uts);
@@ -664,14 +664,15 @@  static int ut_run_test(struct unit_test_state *uts, struct unit_test *test,
 	ut_set_state(NULL);
 
 	if (uts->leak_check) {
-		struct mallinfo leak_after;
-		int diff;
-
-		leak_after = mallinfo();
-		diff = leak_after.uordblks - leak_before.uordblks;
-		if (diff)
-			printf("Leak: %d bytes: %s%s\n", diff, test_name,
-			       note);
+		int leaks;
+
+		leaks = malloc_leak_check_count(&leak_snap);
+		if (leaks > 0) {
+			printf("Leak: %d allocs\n", leaks);
+			malloc_leak_check_end(&leak_snap);
+		} else {
+			malloc_leak_check_free(&leak_snap);
+		}
 	}
 
 	if (uts->emit_result) {