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
/memcheck/tests/Makefile
/memcheck/tests/Makefile.in
/memcheck/tests/mallinfo
+/memcheck/tests/mallinfo2
/memcheck/tests/malloc1
/memcheck/tests/malloc2
/memcheck/tests/malloc3
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
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
getaddrinfo \
klogctl \
mallinfo \
+ mallinfo2 \
memchr \
memfd_create \
memset \
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);
10190 PANIC
10200 MALLOC_STATS
10210 MALLINFO
+ 10215 MALLINFO2
10220 DEFAULT_ZONE
10230 CREATE_ZONE
10240 ZONE_FROM_PTR
#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)
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);
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,
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.
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;
};
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 \
leak-segv-jmp \
long-supps \
mallinfo \
+ mallinfo2 \
malloc_free_fill \
malloc_usable malloc1 malloc2 malloc3 manuel1 manuel2 manuel3 \
match-overrun \
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@
--- /dev/null
+#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;
+}
--- /dev/null
+
+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)
--- /dev/null
+prog: mallinfo2
+args: -q
+stderr_filter: filter_allocs