]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Implement and override mallinfo2
authorMartin Cermak <mcermak@redhat.com>
Fri, 18 Jul 2025 15:11:49 +0000 (17:11 +0200)
committerMark Wielaard <mark@klomp.org>
Thu, 31 Jul 2025 11:10:41 +0000 (13:10 +0200)
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

13 files changed:
.gitignore
NEWS
auxprogs/ltp-excludes.txt
configure.ac
coregrind/m_mallocfree.c
coregrind/m_replacemalloc/vg_replace_malloc.c
coregrind/m_scheduler/scheduler.c
coregrind/pub_core_mallocfree.h
coregrind/pub_core_replacemalloc.h
memcheck/tests/Makefile.am
memcheck/tests/mallinfo2.c [new file with mode: 0644]
memcheck/tests/mallinfo2.stderr.exp [new file with mode: 0644]
memcheck/tests/mallinfo2.vgtest [new file with mode: 0644]

index 0283b8d5b7e99f2db79dae0a1361781f1629dbcf..e48a2ab0ed169d6deb8d567091733a738f85705c 100644 (file)
 /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 00c785dfdb9cfba135ac7d662f7a7a7da2661aee..fe9de908f793d5d8dbf92619e97df033da5dbc4f 100644 (file)
--- 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
 
index b03111e20daf23aafa532fe3056c536daea55d6d..0d00bab8a6dda18106131f4a6a2fd23e06c066a1 100644 (file)
@@ -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
index 804493c2f20025a5507c8e3aa73a3aebb8d32b11..6183179db141fbbcc1f2025eb16466b84837dae0 100755 (executable)
@@ -4952,6 +4952,7 @@ AC_CHECK_FUNCS([     \
         getaddrinfo  \
         klogctl      \
         mallinfo     \
+        mallinfo2    \
         memchr       \
         memfd_create \
         memset       \
index dbbcb93961ff7717aa6b2b2a7797376a56e68591..e7c80af71048ef3328ce81ee66f2524f58548286 100644 (file)
@@ -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);
index aff2d27b3c1cc45ea3902c132e6efdff7fa597b9..808096152b532afc0a11f9c86ef68bfd21a626d9 100644 (file)
    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)
index 1623dda5a01099806b2d783e1b8989a6499d5824..1e77944cdde7baff3405ca9b78e7358068ab14a9 100644 (file)
@@ -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);
 
index df9648cea47b1ee429be15498c72f07be1c49618..3ae9eb486a976d8bd668b2e099654a303f6e08aa 100644 (file)
@@ -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.
index f26884c4fdd26a8468782c7570c3668c7f226172..4f9c5bb1a3275eb7020a407e075e6d8c3e1367f4 100644 (file)
@@ -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;
 };
index aceed97b279b311abc0578971138f0732013e950..91d58b48b8ad32fdc32b366c081f74a9e8f1d1d3 100644 (file)
@@ -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 (file)
index 0000000..23667a5
--- /dev/null
@@ -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 (file)
index 0000000..65f7e5b
--- /dev/null
@@ -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 (file)
index 0000000..ba76920
--- /dev/null
@@ -0,0 +1,3 @@
+prog: mallinfo2
+args: -q
+stderr_filter: filter_allocs