Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | // SPDX-License-Identifier: GPL-2.0+ /* * Test for 'malloc' command * * Copyright 2025 Canonical Ltd * Written by Simon Glass <simon.glass@canonical.com> */ #include <malloc.h> #include <mapmem.h> #include <dm/test.h> #include <test/cmd.h> #include <test/ut.h> /* Test 'malloc info' command */ static int cmd_test_malloc_info(struct unit_test_state *uts) { struct malloc_info info; ut_assertok(malloc_get_info(&info)); ut_assert(info.total_bytes >= CONFIG_SYS_MALLOC_LEN); ut_assert(info.in_use_bytes < info.total_bytes); ut_assert(info.malloc_count > 0); ut_assertok(run_command("malloc info", 0)); ut_assert_nextlinen("total bytes = "); ut_assert_nextlinen("in use bytes = "); ut_assert_nextlinen("malloc count = "); ut_assert_nextlinen("free count = "); ut_assert_nextlinen("realloc count = "); ut_assert_console_end(); return 0; } CMD_TEST(cmd_test_malloc_info, UTF_CONSOLE); /* Test 'malloc dump' command */ static int cmd_test_malloc_dump(struct unit_test_state *uts) { /* this takes a long time to dump, with truetype enabled, so skip it */ return -EAGAIN; ut_assertok(run_command("malloc dump", 0)); ut_assert_nextlinen("Heap dump: "); ut_assert_nextline("%12s %10s %s", "Address", "Size", "Status"); ut_assert_nextline("----------------------------------"); ut_assert_nextline("%12lx %10x (chunk header)", mem_malloc_start, 0x10); ut_assert_skip_to_line("----------------------------------"); ut_assert_nextlinen("Used: "); ut_assert_nextlinen("Free: "); ut_assert_console_end(); return 0; } CMD_TEST(cmd_test_malloc_dump, UTF_CONSOLE); /* Test 'malloc leak' command using the C API directly */ static int cmd_test_malloc_leak(struct unit_test_state *uts) { struct malloc_leak_snap snap = {}; ulong chunk_addr; size_t chunk_sz; void *ptr; int ret; /* Take a snapshot, then check with no leaks */ ut_assertok(malloc_leak_check_start(&snap)); ut_assert(snap.count > 0); ut_asserteq(0, malloc_leak_check_count(&snap)); /* Allocate something and check it is detected */ ptr = malloc(0x42); ut_assertnonnull(ptr); ut_asserteq(1, malloc_leak_check_count(&snap)); /* Verify freeing clears the leak */ free(ptr); ut_asserteq(0, malloc_leak_check_count(&snap)); /* Re-allocate so end has something to print */ ptr = malloc(0x42); ut_assertnonnull(ptr); /* End should print the leaked allocation and free the snapshot */ ret = malloc_leak_check_end(&snap); ut_asserteq(1, ret); /* * Check the output line shows the correct chunk address and chunk * size. The chunk address is the malloc pointer minus the mcheck * header. The caller name is only available with mcheck. */ chunk_addr = (ulong)ptr - malloc_mcheck_hdr_size(); chunk_sz = malloc_chunk_size(ptr); if (IS_ENABLED(CONFIG_MCHECK_HEAP_PROTECTION)) ut_assert_nextlinen(" %lx %zx %s:", chunk_addr, chunk_sz, __func__); else ut_assert_nextlinen(" %lx %zx ", chunk_addr, chunk_sz); ut_assert_console_end(); ut_assertnull(snap.addr); free(ptr); return 0; } CMD_TEST(cmd_test_malloc_leak, UTF_CONSOLE); #if CONFIG_IS_ENABLED(MCHECK_LOG) /* Test 'malloc log' command */ static int cmd_test_malloc_log(struct unit_test_state *uts) { struct mlog_info info; void *ptr, *ptr2; int seq; ut_assertok(run_command("malloc log start", 0)); ut_assert_nextline("Malloc logging started"); ut_assert_console_end(); /* Get current log position so we know our sequence numbers */ ut_assertok(malloc_log_info(&info)); seq = info.total_count; /* Do allocations with distinctive sizes we can search for */ ptr = malloc(12345); ut_assertnonnull(ptr); ptr2 = realloc(ptr, 23456); ut_assertnonnull(ptr2); free(ptr2); ut_assertok(run_command("malloc log stop", 0)); ut_assert_nextline("Malloc logging stopped"); ut_assert_console_end(); /* Dump the log and find our allocations by sequence number and size */ ut_assertok(run_command("malloc log", 0)); ut_assert_nextlinen("Malloc log: "); ut_assert_nextline("%4s %-8s %10s %8s %s", "Seq", "Type", "Address", "Size", "Caller"); ut_assert_nextline("---- -------- ---------- -------- ------"); /* 12345 = 0x3039, 23456 = 0x5ba0 */ ut_assert_skip_to_linen("%4d alloc %10lx 3039", seq, (ulong)map_to_sysmem(ptr)); ut_assert_skip_to_linen("%4d realloc %10lx 5ba0", seq + 1, (ulong)map_to_sysmem(ptr2)); ut_assert_skip_to_linen("%4d free %10lx 0", seq + 2, (ulong)map_to_sysmem(ptr2)); console_record_reset_enable(); /* discard remaining output */ return 0; } CMD_TEST(cmd_test_malloc_log, UTF_CONSOLE); #endif /* MCHECK_LOG */ |