From: Mark W. <ma...@so...> - 2025-07-31 11:26:19
|
https://sourceware.org/cgit/valgrind/commit/?id=ab551753fad6a87acbb8a87a80ed5f5578bfd29c commit ab551753fad6a87acbb8a87a80ed5f5578bfd29c Author: Martin Cermak <mc...@re...> Date: Fri Jul 18 17:11:49 2025 +0200 Implement and override mallinfo2 Implement and override mallinfo2. Add a testcase covering mallinfo2. Exclude irrelevant LTP tests trying to cover mallinfo2. https://bugs.kde.org/show_bug.cgi?id=506967 Diff: --- .gitignore | 1 + NEWS | 1 + auxprogs/ltp-excludes.txt | 5 + configure.ac | 1 + coregrind/m_mallocfree.c | 35 +++++++ coregrind/m_replacemalloc/vg_replace_malloc.c | 28 ++++++ coregrind/m_scheduler/scheduler.c | 1 + coregrind/pub_core_mallocfree.h | 16 ++++ coregrind/pub_core_replacemalloc.h | 1 + memcheck/tests/Makefile.am | 3 + memcheck/tests/mallinfo2.c | 133 ++++++++++++++++++++++++++ memcheck/tests/mallinfo2.stderr.exp | 11 +++ memcheck/tests/mallinfo2.vgtest | 3 + 13 files changed, 239 insertions(+) diff --git a/.gitignore b/.gitignore index 0283b8d5b7..e48a2ab0ed 100644 --- a/.gitignore +++ b/.gitignore @@ -943,6 +943,7 @@ /memcheck/tests/Makefile /memcheck/tests/Makefile.in /memcheck/tests/mallinfo +/memcheck/tests/mallinfo2 /memcheck/tests/malloc1 /memcheck/tests/malloc2 /memcheck/tests/malloc3 diff --git a/NEWS b/NEWS index 00c785dfdb..fe9de908f7 100644 --- a/NEWS +++ b/NEWS @@ -61,6 +61,7 @@ are not entered into bugzilla tend to get forgotten about or ignored. 506910 openat2 with RESOLVE_NO_MAGICLINKS succeeds on /proc/self/exe 506928 Wrap (deprecated) linux specific ustat syscall 506930 valgrind allows SIGKILL being reset to SIG_DFL +506967 Implement and override mallinfo2 506970 mmap needs an EBADF fd_allowed check 507173 s390x: Crash when constant folding is disabled diff --git a/auxprogs/ltp-excludes.txt b/auxprogs/ltp-excludes.txt index b03111e20d..0d00bab8a6 100644 --- a/auxprogs/ltp-excludes.txt +++ b/auxprogs/ltp-excludes.txt @@ -29,3 +29,8 @@ fcntl36_64 clone08 close_range02 kcmp03 +# Test fails because it tests something valgrind doesn't support: +# We don't have fastbins so smblks & fsmblks are always 0. Also we +# don't have a separate mmap allocator so set hblks & hblkhd to 0. +mallinfo02 +mallinfo2_01 diff --git a/configure.ac b/configure.ac index 804493c2f2..6183179db1 100755 --- a/configure.ac +++ b/configure.ac @@ -4952,6 +4952,7 @@ AC_CHECK_FUNCS([ \ getaddrinfo \ klogctl \ mallinfo \ + mallinfo2 \ memchr \ memfd_create \ memset \ diff --git a/coregrind/m_mallocfree.c b/coregrind/m_mallocfree.c index dbbcb93961..e7c80af710 100644 --- a/coregrind/m_mallocfree.c +++ b/coregrind/m_mallocfree.c @@ -2433,6 +2433,41 @@ void VG_(mallinfo) ( ThreadId tid, struct vg_mallinfo* mi ) mi->keepcost = 0; // may want some value in here } +// The aforementioned older function, mallinfo(), is deprecated since the type +// used for the fields is too small. +void VG_(mallinfo2) ( ThreadId tid, struct vg_mallinfo2* mi ) +{ + UWord i, free_blocks, free_blocks_size; + Arena* a = arenaId_to_ArenaP(VG_AR_CLIENT); + + // Traverse free list and calculate free blocks statistics. + // This may seem slow but glibc works the same way. + free_blocks_size = free_blocks = 0; + for (i = 0; i < N_MALLOC_LISTS; i++) { + Block* b = a->freelist[i]; + if (b == NULL) continue; + for (;;) { + free_blocks++; + free_blocks_size += (UWord)get_pszB(a, b); + b = get_next_b(b); + if (b == a->freelist[i]) break; + } + } + + // We don't have fastbins so smblks & fsmblks are always 0. Also we don't + // have a separate mmap allocator so set hblks & hblkhd to 0. + mi->arena = a->stats__bytes_mmaped; + mi->ordblks = free_blocks + VG_(free_queue_length); + mi->smblks = 0; + mi->hblks = 0; + mi->hblkhd = 0; + mi->usmblks = 0; + mi->fsmblks = 0; + mi->uordblks = a->stats__bytes_on_loan - VG_(free_queue_volume); + mi->fordblks = free_blocks_size + VG_(free_queue_volume); + mi->keepcost = 0; // may want some value in here +} + SizeT VG_(arena_redzone_size) ( ArenaId aid ) { ensure_mm_init (VG_AR_CLIENT); diff --git a/coregrind/m_replacemalloc/vg_replace_malloc.c b/coregrind/m_replacemalloc/vg_replace_malloc.c index aff2d27b3c..808096152b 100644 --- a/coregrind/m_replacemalloc/vg_replace_malloc.c +++ b/coregrind/m_replacemalloc/vg_replace_malloc.c @@ -103,6 +103,7 @@ 10190 PANIC 10200 MALLOC_STATS 10210 MALLINFO + 10215 MALLINFO2 10220 DEFAULT_ZONE 10230 CREATE_ZONE 10240 ZONE_FROM_PTR @@ -2523,6 +2524,33 @@ static void panic(const char *str) #endif +/*---------------------- mallinfo2 ----------------------*/ + +// mi must be static; if it is auto then Memcheck thinks it is +// uninitialised when used by the caller of this function, because Memcheck +// doesn't know that the call to mallinfo2 fills in mi. +#define MALLINFO2(soname, fnname) \ + \ + struct vg_mallinfo2 VG_REPLACE_FUNCTION_EZU(10215,soname,fnname) ( void ); \ + struct vg_mallinfo2 VG_REPLACE_FUNCTION_EZU(10215,soname,fnname) ( void ) \ + { \ + static struct vg_mallinfo2 mi; \ + DO_INIT; \ + MALLOC_TRACE("mallinfo2()\n"); \ + (void)VALGRIND_NON_SIMD_CALL1( info.mallinfo2, &mi ); \ + return mi; \ + } + +#if defined(VGO_linux) + MALLINFO2(VG_Z_LIBC_SONAME, mallinfo2); + MALLINFO2(SO_SYN_MALLOC, mallinfo2); + +#elif defined(VGO_darwin) + //MALLINFO2(VG_Z_LIBC_SONAME, mallinfo2); + +#endif + + /*------------------ Darwin zone stuff ------------------*/ #if defined(VGO_darwin) diff --git a/coregrind/m_scheduler/scheduler.c b/coregrind/m_scheduler/scheduler.c index 1623dda5a0..1e77944cdd 100644 --- a/coregrind/m_scheduler/scheduler.c +++ b/coregrind/m_scheduler/scheduler.c @@ -2147,6 +2147,7 @@ void do_client_request ( ThreadId tid ) info->tl_malloc_usable_size = VG_(tdict).tool_malloc_usable_size; info->mallinfo = VG_(mallinfo); + info->mallinfo2 = VG_(mallinfo2); info->clo_trace_malloc = VG_(clo_trace_malloc); info->clo_realloc_zero_bytes_frees = VG_(clo_realloc_zero_bytes_frees); diff --git a/coregrind/pub_core_mallocfree.h b/coregrind/pub_core_mallocfree.h index df9648cea4..3ae9eb486a 100644 --- a/coregrind/pub_core_mallocfree.h +++ b/coregrind/pub_core_mallocfree.h @@ -106,6 +106,21 @@ struct vg_mallinfo { int keepcost; /* top-most, releasable (via malloc_trim) space */ }; +/* This struct definition MUST match the system one. */ +/* SVID2/XPG mallinfo structure */ +struct vg_mallinfo2 { + SizeT arena; /* total space allocated from system */ + SizeT ordblks; /* number of non-inuse chunks */ + SizeT smblks; /* unused -- always zero */ + SizeT hblks; /* number of mmapped regions */ + SizeT hblkhd; /* total space in mmapped regions */ + SizeT usmblks; /* unused -- always zero */ + SizeT fsmblks; /* unused -- always zero */ + SizeT uordblks; /* total allocated space */ + SizeT fordblks; /* total non-inuse space */ + SizeT keepcost; /* top-most, releasable (via malloc_trim) space */ +}; + extern void* VG_(arena_malloc) ( ArenaId arena, const HChar* cc, SizeT nbytes ); extern void VG_(arena_free) ( ArenaId arena, void* ptr ); extern void* VG_(arena_calloc) ( ArenaId arena, const HChar* cc, @@ -132,6 +147,7 @@ extern SizeT VG_(arena_malloc_usable_size) ( ArenaId aid, void* payload ); extern SizeT VG_(arena_redzone_size) ( ArenaId aid ); extern void VG_(mallinfo) ( ThreadId tid, struct vg_mallinfo* mi ); +extern void VG_(mallinfo2) ( ThreadId tid, struct vg_mallinfo2* mi ); // VG_(arena_perm_malloc) is for permanent allocation of small blocks. // See VG_(perm_malloc) in pub_tool_mallocfree.h for more details. diff --git a/coregrind/pub_core_replacemalloc.h b/coregrind/pub_core_replacemalloc.h index f26884c4fd..4f9c5bb1a3 100644 --- a/coregrind/pub_core_replacemalloc.h +++ b/coregrind/pub_core_replacemalloc.h @@ -54,6 +54,7 @@ struct vg_mallocfunc_info { void* (*tl_realloc) (ThreadId tid, void* p, SizeT size); SizeT (*tl_malloc_usable_size) (ThreadId tid, void* payload); void (*mallinfo) (ThreadId tid, struct vg_mallinfo* mi); + void (*mallinfo2) (ThreadId tid, struct vg_mallinfo2* mi); Bool clo_trace_malloc; Bool clo_realloc_zero_bytes_frees; }; diff --git a/memcheck/tests/Makefile.am b/memcheck/tests/Makefile.am index aceed97b27..91d58b48b8 100644 --- a/memcheck/tests/Makefile.am +++ b/memcheck/tests/Makefile.am @@ -261,6 +261,7 @@ EXTRA_DIST = \ long_namespace_xml.stderr.exp long_namespace_xml.stderr.exp-freebsd \ long-supps.vgtest long-supps.stderr.exp long-supps.supp \ mallinfo.stderr.exp mallinfo.vgtest \ + mallinfo2.stderr.exp mallinfo2.vgtest \ malloc_free_fill.vgtest \ malloc_free_fill.stderr.exp \ malloc_usable.stderr.exp malloc_usable.vgtest \ @@ -521,6 +522,7 @@ check_PROGRAMS = \ leak-segv-jmp \ long-supps \ mallinfo \ + mallinfo2 \ malloc_free_fill \ malloc_usable malloc1 malloc2 malloc3 manuel1 manuel2 manuel3 \ match-overrun \ @@ -682,6 +684,7 @@ bug472219_CFLAGS = $(AM_CFLAGS) @FLAG_W_NO_UNINITIALIZED@ calloc_overflow_CFLAGS = ${AM_CFLAGS} @FLAG_W_NO_ALLOC_SIZE_LARGER_THAN@ malloc_usable_CFLAGS = ${AM_CFLAGS} @FLAG_W_NO_MAYBE_UNINITIALIZED@ @FLAG_W_NO_UNINITIALIZED@ mallinfo_CFLAGS = $(AM_CFLAGS) -Wno-deprecated-declarations +mallinfo2_CFLAGS = $(AM_CFLAGS) -Wno-deprecated-declarations malloc3_CFLAGS = $(AM_CFLAGS) @FLAG_W_NO_ALLOC_SIZE_LARGER_THAN@ sbfragment_CFLAGS = $(AM_CFLAGS) -Wno-deprecated-declarations strchr_CFLAGS = $(AM_CFLAGS) @FLAG_W_NO_UNINITIALIZED@ diff --git a/memcheck/tests/mallinfo2.c b/memcheck/tests/mallinfo2.c new file mode 100644 index 0000000000..23667a5b1d --- /dev/null +++ b/memcheck/tests/mallinfo2.c @@ -0,0 +1,133 @@ +#include "tests/malloc.h" +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> // getopt() +#include "../config.h" + + +static int s_quiet = 0; + + +#if defined(HAVE_MALLINFO2) +static size_t check(size_t min, size_t max) +{ + struct mallinfo2 mi; + size_t used; + + mi = mallinfo2(); + + if (! s_quiet) + { + printf("arena = %d\n", mi.arena); /* non-mmapped space allocated from system */ + printf("ordblks = %d\n", mi.ordblks); /* number of free chunks */ + printf("smblks = %d\n", mi.smblks); /* number of fastbin blocks */ + printf("hblks = %d\n", mi.hblks); /* number of mmapped regions */ + printf("hblkhd = %d\n", mi.hblkhd); /* space in mmapped regions */ + printf("usmblks = %d\n", mi.usmblks); /* maximum total allocated space */ + printf("fsmblks = %d\n", mi.fsmblks); /* space available in freed fastbin blocks */ + printf("uordblks = %d\n", mi.uordblks); /* total allocated space */ + printf("fordblks = %d\n", mi.fordblks); /* total free space */ + printf("keepcost = %d\n", mi.keepcost); /* top-most, releasable (via malloc_trim) space */ + printf("(min = %zu, max = %zu)\n", min, max); + printf("\n"); + } + + // size checks + used = mi.uordblks + mi.hblkhd; + if (used < min) + exit(1); + + if (used > max) + exit(2); + + // used should be reasonably close to min + // define "reasonably" as within 20% + if (used/5*4 > min) + exit(3); + + // sanity checks + if ((mi.ordblks == 0) != (mi.fordblks == 0)) + exit(10); + + if ((mi.smblks == 0) != (mi.fsmblks == 0)) + exit(11); + + if ((mi.hblks == 0) != (mi.hblkhd == 0)) + exit(12); + + if (mi.keepcost > mi.fordblks) + exit(13); + + if (mi.fsmblks > mi.fordblks) + exit(14); + + // arena should be reasonably close to fordblks + uordblks + if (mi.arena < mi.fordblks + mi.uordblks) + exit(15); + + if (mi.arena/5*4 > mi.fordblks + mi.uordblks) + exit(16); + + return used; +} +#else +static size_t check(size_t min, size_t max) +{ + if (! s_quiet) + { + printf("mallinfo() is not supported on this platform.\n"); + printf("\n"); + } + return 0; +} +#endif + +int main(int argc, char** argv) +{ + void* ptr[40]; + int i; + size_t min, max; + int optchar; + + while ((optchar = getopt(argc, argv, "q")) != EOF) + { + switch (optchar) + { + case 'q': + s_quiet = 1; + break; + default: + fprintf(stderr, "Usage: %s [-q].\n", argv[0]); + return 1; + } + } + + min = 0; + for (i = 1; i <= 40; i++) + { + int size = i * i * 8; + min += size; + ptr[i - 1] = malloc(size); + }; + + max = check(min, (size_t)-1); + + for (i = 1; i <= 20; i++) + { + int size = i * i * 8; + min -= size; + max -= size; + free(ptr[i - 1]); + }; + + check(min, max); + + for ( ; i <= 40; i++) + { + free(ptr[i - 1]); + } + + fprintf(stderr, "Success.\n"); + + return 0; +} diff --git a/memcheck/tests/mallinfo2.stderr.exp b/memcheck/tests/mallinfo2.stderr.exp new file mode 100644 index 0000000000..65f7e5b13d --- /dev/null +++ b/memcheck/tests/mallinfo2.stderr.exp @@ -0,0 +1,11 @@ + +Success. + +HEAP SUMMARY: + in use at exit: ... bytes in ... blocks + total heap usage: ... allocs, ... frees, ... bytes allocated + +For a detailed leak analysis, rerun with: --leak-check=full + +For lists of detected and suppressed errors, rerun with: -s +ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) diff --git a/memcheck/tests/mallinfo2.vgtest b/memcheck/tests/mallinfo2.vgtest new file mode 100644 index 0000000000..ba76920727 --- /dev/null +++ b/memcheck/tests/mallinfo2.vgtest @@ -0,0 +1,3 @@ +prog: mallinfo2 +args: -q +stderr_filter: filter_allocs |