[PATCH v3] malloc: Support hugepages in mremap_chunk

William Hunt william.hunt@arm.com
Wed Aug 20 19:46:47 GMT 2025


Add mremap_chunk support for mmap()ed chunks using hugepages by accounting for 
their alignment, to prevent the mremap call failing in most cases where the 
size passed is not a hugepage size multiple. It also improves robustness for 
reallocating hugepages since mremap is much less likely to fail, so running 
out of memory when reallocating a larger size and having to copy the old 
contents after mremap fails is also less likely.

To track whether an mmap()ed chunk uses hugepages, have a flag in the lowest 
bit of the mchunk_prev_size field which is set after a call to sysmalloc_mmap, 
and accessed later in mremap_chunk. Create macros for getting and setting this 
bit, and for mapping the bit off when accessing the field for mmap()ed chunks. 
Since the alignment cannot be lower than 8 bits, this flag cannot affect the 
alignment data. 

Add malloc/tst-tcfree4-malloc-check to the tests-exclude-malloc-check list as 
malloc-check prevents the tcache from being used to store chunks. This test 
caused failures due to a bug in mem2chunk_check to be fixed in a later patch. 

Changes from v1:
- Change macros to inlined functions.
- Added malloc/tst-tcfree4 to tests-exclude-malloc-check as tcache is disabled.
Changes from v2:
- Removed a first mem2chunk_check fix, should be fully fixed in another patch. 

Passed regress for THPs, neither and HPs using overcommit pages, OK for commit?
---
 malloc/Makefile       |  1 +
 malloc/malloc-check.c |  4 ++--
 malloc/malloc.c       | 41 +++++++++++++++++++++++++++++++++++------
 3 files changed, 38 insertions(+), 8 deletions(-)

diff --git a/malloc/Makefile b/malloc/Makefile
index 83f6c873e8..a9a0e87264 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -114,6 +114,7 @@ tests-exclude-malloc-check = \
   tst-memalign-3 \
   tst-mxfast \
   tst-safe-linking \
+  tst-tcfree4 \
 # tests-exclude-malloc-check
 
 # Run all tests with MALLOC_CHECK_=3
diff --git a/malloc/malloc-check.c b/malloc/malloc-check.c
index 9532316a29..7731eaeec5 100644
--- a/malloc/malloc-check.c
+++ b/malloc/malloc-check.c
@@ -151,8 +151,8 @@ mem2chunk_check (void *mem, unsigned char **magic_p)
            offset != 0x200 && offset != 0x400 && offset != 0x800 && offset != 0x1000 &&
            offset < 0x2000) ||
           !chunk_is_mmapped (p) || prev_inuse (p) ||
-          ((((unsigned long) p - prev_size (p)) & page_mask) != 0) ||
-          ((prev_size (p) + sz) & page_mask) != 0)
+          ((((unsigned long) p - prev_size_mmap (p)) & page_mask) != 0) ||
+          ((prev_size_mmap (p) + sz) & page_mask) != 0)
         return NULL;
 
       for (sz = CHUNK_HDR_SZ + memsize (p) - 1;
diff --git a/malloc/malloc.c b/malloc/malloc.c
index e08873cad5..55688d4319 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -1477,6 +1477,30 @@ tag_new_usable (void *ptr)
   return ptr;
 }
 
+/* HP page used for an mmap()'ed chunk. */
+#define MMAP_HP 0x1
+
+/* Check for HP usage from an mmap()'ed chunk. */
+static __always_inline bool
+mmap_is_hp (mchunkptr p)
+{
+  return prev_size (p) & MMAP_HP;
+}
+
+/* Set HP advised field for an mmap()'ed chunk. */
+static __always_inline void
+set_mmap_is_hp (mchunkptr p)
+{
+  prev_size (p) |= MMAP_HP;
+}
+
+/* Get an mmap()ed chunk's offset, ignoring huge page bits. */
+static __always_inline size_t
+prev_size_mmap (mchunkptr p)
+{
+  return prev_size (p) & ~MMAP_HP;
+}
+
 /*
    -------------------- Internal data structures --------------------
 
@@ -2105,7 +2129,7 @@ do_check_chunk (mstate av, mchunkptr p)
   else
     {
       /* chunk is page-aligned */
-      assert (((prev_size (p) + sz) & (GLRO (dl_pagesize) - 1)) == 0);
+      assert (((prev_size_mmap (p) + sz) & (GLRO (dl_pagesize) - 1)) == 0);
       /* mem is aligned */
       assert (!misaligned_chunk (p));
     }
@@ -2429,6 +2453,11 @@ sysmalloc_mmap (INTERNAL_SIZE_T nb, size_t pagesize, int extra_flags)
   set_prev_size (p, padding);
   set_head (p, (size - padding) | IS_MMAPPED);
 
+  /* Must also check whether huge pages were used in the mmap call
+     and this is not the fallback call after using huge pages failed */
+  if (__glibc_unlikely (extra_flags & mp_.hp_flags))
+    set_mmap_is_hp (p);
+
   /* update statistics */
   int new = atomic_fetch_add_relaxed (&mp_.n_mmaps, 1) + 1;
   atomic_max (&mp_.max_n_mmaps, new);
@@ -2982,8 +3011,8 @@ munmap_chunk (mchunkptr p)
   assert (chunk_is_mmapped (p));
 
   uintptr_t mem = (uintptr_t) chunk2mem (p);
-  uintptr_t block = (uintptr_t) p - prev_size (p);
-  size_t total_size = prev_size (p) + size;
+  uintptr_t block = (uintptr_t) p - prev_size_mmap (p);
+  size_t total_size = prev_size_mmap (p) + size;
   /* Unfortunately we have to do the compilers job by hand here.  Normally
      we would test BLOCK and TOTAL-SIZE separately for compliance with the
      page size.  But gcc does not recognize the optimization possibility
@@ -3007,8 +3036,8 @@ munmap_chunk (mchunkptr p)
 static mchunkptr
 mremap_chunk (mchunkptr p, size_t new_size)
 {
-  size_t pagesize = GLRO (dl_pagesize);
-  INTERNAL_SIZE_T offset = prev_size (p);
+  size_t pagesize = mmap_is_hp (p) ? mp_.hp_pagesize : GLRO (dl_pagesize);
+  INTERNAL_SIZE_T offset = prev_size_mmap (p);
   INTERNAL_SIZE_T size = chunksize (p);
   char *cp;
 
@@ -3040,7 +3069,7 @@ mremap_chunk (mchunkptr p, size_t new_size)
 
   assert (!misaligned_chunk (p));
 
-  assert (prev_size (p) == offset);
+  assert (prev_size_mmap (p) == offset);
   set_head (p, (new_size - offset) | IS_MMAPPED);
 
   INTERNAL_SIZE_T new;
-- 
2.43.0



More information about the Libc-alpha mailing list