malloc: Decorate malloc maps

Add anonymous mmap annotations on loader malloc, malloc when it
allocates memory with mmap, and on malloc arena.  The /proc/self/maps
will now print:

   [anon: glibc: malloc arena]
   [anon: glibc: malloc]
   [anon: glibc: loader malloc]

On arena allocation, glibc annotates only the read/write mapping.

Checked on x86_64-linux-gnu and aarch64-linux-gnu.
Reviewed-by: DJ Delorie <dj@redhat.com>
This commit is contained in:
Adhemerval Zanella 2023-11-01 09:56:08 -03:00
parent 6afce56c19
commit fee9e40a8d
6 changed files with 55 additions and 0 deletions

View File

@ -2983,3 +2983,7 @@ $(objpfx)tst-dlclose-lazy.out: \
$(objpfx)tst-dlclose-lazy-mod1.so $(objpfx)tst-dlclose-lazy-mod2.so $(objpfx)tst-dlclose-lazy-mod1.so $(objpfx)tst-dlclose-lazy-mod2.so
$(objpfx)tst-decorate-maps: $(shared-thread-library) $(objpfx)tst-decorate-maps: $(shared-thread-library)
tst-decorate-maps-ENV = \
GLIBC_TUNABLES=glibc.malloc.arena_max=8:glibc.malloc.mmap_threshold=1024
tst-decorate-maps-ARGS = 8

View File

@ -26,6 +26,7 @@
#include <string.h> #include <string.h>
#include <ldsodefs.h> #include <ldsodefs.h>
#include <malloc/malloc-internal.h> #include <malloc/malloc-internal.h>
#include <setvmaname.h>
static void *alloc_ptr, *alloc_end, *alloc_last_block; static void *alloc_ptr, *alloc_end, *alloc_last_block;
@ -60,6 +61,7 @@ __minimal_malloc (size_t n)
MAP_ANON|MAP_PRIVATE, -1, 0); MAP_ANON|MAP_PRIVATE, -1, 0);
if (page == MAP_FAILED) if (page == MAP_FAILED)
return NULL; return NULL;
__set_vma_name (page, nup, " glibc: loader malloc");
if (page != alloc_end) if (page != alloc_end)
alloc_ptr = page; alloc_ptr = page;
alloc_end = page + nup; alloc_end = page + nup;

View File

@ -32,15 +32,21 @@
static pthread_barrier_t b; static pthread_barrier_t b;
static int expected_n_arenas;
static void * static void *
tf (void *closure) tf (void *closure)
{ {
void *p = xmalloc (1024);
/* Wait the thread startup, so thread stack is allocated. */ /* Wait the thread startup, so thread stack is allocated. */
xpthread_barrier_wait (&b); xpthread_barrier_wait (&b);
/* Wait the test to read the process mapping. */ /* Wait the test to read the process mapping. */
xpthread_barrier_wait (&b); xpthread_barrier_wait (&b);
free (p);
return NULL; return NULL;
} }
@ -48,6 +54,9 @@ struct proc_maps_t
{ {
int n_def_threads; int n_def_threads;
int n_user_threads; int n_user_threads;
int n_arenas;
int n_malloc_mmap;
int n_loader_malloc_mmap;
}; };
static struct proc_maps_t static struct proc_maps_t
@ -69,6 +78,12 @@ read_proc_maps (void)
r.n_def_threads++; r.n_def_threads++;
else if (strstr (line, "[anon: glibc: pthread user stack:") != NULL) else if (strstr (line, "[anon: glibc: pthread user stack:") != NULL)
r.n_user_threads++; r.n_user_threads++;
else if (strstr (line, "[anon: glibc: malloc arena]") != NULL)
r.n_arenas++;
else if (strstr (line, "[anon: glibc: malloc]") != NULL)
r.n_malloc_mmap++;
else if (strstr (line, "[anon: glibc: loader malloc]") != NULL)
r.n_loader_malloc_mmap++;
} }
free (line); free (line);
xfclose (f); xfclose (f);
@ -90,6 +105,9 @@ do_test_threads (bool set_guard)
xpthread_barrier_init (&b, NULL, num_threads + 1); xpthread_barrier_init (&b, NULL, num_threads + 1);
/* Issue a large malloc to trigger a mmap call. */
void *p = xmalloc (256 * 1024);
pthread_t thr[num_threads]; pthread_t thr[num_threads];
{ {
int i = 0; int i = 0;
@ -128,6 +146,10 @@ do_test_threads (bool set_guard)
struct proc_maps_t r = read_proc_maps (); struct proc_maps_t r = read_proc_maps ();
TEST_COMPARE (r.n_def_threads, num_def_threads); TEST_COMPARE (r.n_def_threads, num_def_threads);
TEST_COMPARE (r.n_user_threads, num_user_threads); TEST_COMPARE (r.n_user_threads, num_user_threads);
TEST_COMPARE (r.n_arenas, expected_n_arenas);
TEST_COMPARE (r.n_malloc_mmap, 1);
/* On some architectures the loader might use more than one page. */
TEST_VERIFY (r.n_loader_malloc_mmap >= 1);
} }
/* Let the threads finish. */ /* Let the threads finish. */
@ -140,9 +162,23 @@ do_test_threads (bool set_guard)
struct proc_maps_t r = read_proc_maps (); struct proc_maps_t r = read_proc_maps ();
TEST_COMPARE (r.n_def_threads, 0); TEST_COMPARE (r.n_def_threads, 0);
TEST_COMPARE (r.n_user_threads, 0); TEST_COMPARE (r.n_user_threads, 0);
TEST_COMPARE (r.n_arenas, expected_n_arenas);
TEST_COMPARE (r.n_malloc_mmap, 1);
TEST_VERIFY (r.n_loader_malloc_mmap >= 1);
} }
free (p);
} }
static void
do_prepare (int argc, char *argv[])
{
TEST_VERIFY_EXIT (argc == 2);
expected_n_arenas = strtol (argv[1], NULL, 10);
expected_n_arenas = expected_n_arenas - 1;
}
#define PREPARE do_prepare
static int static int
do_test (void) do_test (void)
{ {

View File

@ -17,6 +17,7 @@
not, see <https://www.gnu.org/licenses/>. */ not, see <https://www.gnu.org/licenses/>. */
#include <stdbool.h> #include <stdbool.h>
#include <setvmaname.h>
#define TUNABLE_NAMESPACE malloc #define TUNABLE_NAMESPACE malloc
#include <elf/dl-tunables.h> #include <elf/dl-tunables.h>
@ -436,6 +437,9 @@ alloc_new_heap (size_t size, size_t top_pad, size_t pagesize,
return 0; return 0;
} }
/* Only considere the actual usable range. */
__set_vma_name (p2, size, " glibc: malloc arena");
madvise_thp (p2, size); madvise_thp (p2, size);
h = (heap_info *) p2; h = (heap_info *) p2;

View File

@ -218,6 +218,7 @@
#include <sys/sysinfo.h> #include <sys/sysinfo.h>
#include <ldsodefs.h> #include <ldsodefs.h>
#include <setvmaname.h>
#include <unistd.h> #include <unistd.h>
#include <stdio.h> /* needed for malloc_stats */ #include <stdio.h> /* needed for malloc_stats */
@ -2428,6 +2429,8 @@ sysmalloc_mmap (INTERNAL_SIZE_T nb, size_t pagesize, int extra_flags, mstate av)
madvise_thp (mm, size); madvise_thp (mm, size);
#endif #endif
__set_vma_name (mm, size, " glibc: malloc");
/* /*
The offset to the start of the mmapped region is stored in the prev_size The offset to the start of the mmapped region is stored in the prev_size
field of the chunk. This allows us to adjust returned start address to field of the chunk. This allows us to adjust returned start address to
@ -2513,6 +2516,8 @@ sysmalloc_mmap_fallback (long int *s, INTERNAL_SIZE_T nb,
madvise_thp (mbrk, size); madvise_thp (mbrk, size);
#endif #endif
__set_vma_name (mbrk, size, " glibc: malloc");
/* Record that we no longer have a contiguous sbrk region. After the first /* Record that we no longer have a contiguous sbrk region. After the first
time mmap is used as backup, we do not ever rely on contiguous space time mmap is used as backup, we do not ever rely on contiguous space
since this could incorrectly bridge regions. */ since this could incorrectly bridge regions. */

View File

@ -699,6 +699,10 @@ tst-audit-threads-ENV = LD_AUDIT=$(objpfx)tst-audit-threads-mod1.so
tst-setuid1-static-ENV = \ tst-setuid1-static-ENV = \
LD_LIBRARY_PATH=$(ld-library-path):$(common-objpfx)elf:$(common-objpfx)nss LD_LIBRARY_PATH=$(ld-library-path):$(common-objpfx)elf:$(common-objpfx)nss
tst-pthread-proc-maps-ENV = \
GLIBC_TUNABLES=glibc.malloc.arena_max=8:glibc.malloc.mmap_threshold=1024
tst-pthread-proc-maps-ARGS = 8
# The tests here better do not run in parallel. # The tests here better do not run in parallel.
ifeq ($(run-built-tests),yes) ifeq ($(run-built-tests),yes)
ifneq ($(filter %tests,$(MAKECMDGOALS)),) ifneq ($(filter %tests,$(MAKECMDGOALS)),)