[glibc/arm/malloc-mte-v3] malloc: Put malloc_chunk into separate header

Yury Khrustalev via Glibc-cvs <[email protected]> Mon, 1 Jun 2026 11:43:27 +0000 (GMT)
Newsgroups gmane.comp.lib.glibc.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=8b2f748a86e0f8d0499f8b7a219ca5b532aedfa2

commit 8b2f748a86e0f8d0499f8b7a219ca5b532aedfa2
Author: Yury Khrustalev <[email protected]>
Date:   Wed Apr 22 16:30:52 2026 +0100

    malloc: Put malloc_chunk into separate header
    
    Refactor malloc code to extract the definition of malloc_chunk
    struct into a dedicated header  malloc-chunk.h along with basic
    chunk-related macros.
    
    This is a sysdep header.
    
    The new header 'malloc-chunk.h' will include 'malloc-alignment.h'
    that has all dependencies necessary for chunk declarations.
    
    In turn, 'malloc-size.h' will now include 'malloc-chunk.h'. We
    also move size-related definitions from malloc.c into this header.

Diff:
---
 malloc/malloc.c                | 96 ++----------------------------------------
 sysdeps/generic/malloc-chunk.h | 70 ++++++++++++++++++++++++++++++
 sysdeps/generic/malloc-size.h  | 38 ++++++++++++++++-
 3 files changed, 111 insertions(+), 93 deletions(-)

diff --git a/malloc/malloc.c b/malloc/malloc.c
index 674daa1dd5..eb6c0c001f 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -929,12 +929,10 @@ libc_hidden_proto (__libc_mallopt)
 #define RETURN_ADDRESS(X_) (NULL)
 #endif
 
-/* Forward declarations.  */
-struct malloc_chunk;
-typedef struct malloc_chunk* mchunkptr;
-
 /* Internal routines.  */
 
+typedef struct malloc_chunk* mchunkptr;
+
 static void*  _int_malloc(mstate, size_t);
 static void _int_free_chunk (mstate, mchunkptr, INTERNAL_SIZE_T, int);
 static void _int_free_merge_chunk (mstate, mchunkptr, INTERNAL_SIZE_T);
@@ -981,27 +979,7 @@ static size_t musable (void *mem);
 
 
 /*
-  This struct declaration is misleading (but accurate and necessary).
-  It declares a "view" into memory allowing access to necessary
-  fields at known offsets from a given base. See explanation below.
-*/
-
-struct malloc_chunk {
-
-  INTERNAL_SIZE_T      mchunk_prev_size;  /* Size of previous chunk (if free).  */
-  INTERNAL_SIZE_T      mchunk_size;       /* Size in bytes, including overhead. */
-
-  struct malloc_chunk* fd;         /* double links -- used only if free. */
-  struct malloc_chunk* bk;
-
-  /* Only used for large blocks: pointer to next larger size.  */
-  struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
-  struct malloc_chunk* bk_nextsize;
-};
-
-
-/*
-   malloc_chunk details:
+   malloc_chunk details (see malloc-chunk.h):
 
     (The following includes lightly edited explanations by Colin Plumb.)
 
@@ -1107,97 +1085,35 @@ nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   ---------- Size and alignment checks and conversions ----------
 */
 
-/* The chunk header is two SIZE_SZ elements, but this is used widely, so
-   we define it here for clarity later.  */
-#define CHUNK_HDR_SZ (2 * SIZE_SZ)
-
 /* Convert a chunk address to a user mem pointer.  */
 #define chunk2mem(p) ((void*)((char*)(p) + CHUNK_HDR_SZ))
 
 /* Convert a user mem pointer to a chunk address.  */
 #define mem2chunk(mem) ((mchunkptr) (((char*)(mem) - CHUNK_HDR_SZ)))
 
-/* The smallest possible chunk */
-#define MIN_CHUNK_SIZE        (offsetof(struct malloc_chunk, fd_nextsize))
-
-/* The smallest size we can malloc is an aligned minimal chunk */
-
-#define MINSIZE  \
-  (unsigned long)(((MIN_CHUNK_SIZE+MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK))
-
 /* Check if m has acceptable alignment */
 
 #define misaligned_mem(m)  ((uintptr_t)(m) & MALLOC_ALIGN_MASK)
 
-#define misaligned_chunk(p) (misaligned_mem( chunk2mem (p)))
-
-/* pad request bytes into a usable size -- internal version */
-/* Note: This must be a macro that evaluates to a compile time constant
-   if passed a literal constant.  */
-#define request2size(req)                                         \
-  (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE)  ?             \
-   MINSIZE :                                                      \
-   ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)
-
-/* Check if REQ overflows when padded and aligned and if the resulting
-   value is less than PTRDIFF_T.  Returns the requested size or
-   MINSIZE in case the value is less than MINSIZE, or SIZE_MAX if any
-   of the previous checks fail.  */
-static __always_inline size_t
-checked_request2size (size_t req) __nonnull (1)
-{
-  if (__glibc_unlikely (req > PTRDIFF_MAX))
-    return SIZE_MAX;
-  return request2size (req);
-}
+#define misaligned_chunk(p) (misaligned_mem (chunk2mem (p)))
 
 /*
    --------------- Physical chunk operations ---------------
  */
 
 
-/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use */
-#define PREV_INUSE 0x1
-
 /* extract inuse bit of previous chunk */
 #define prev_inuse(p)       ((p)->mchunk_size & PREV_INUSE)
 
-
-/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
-#define IS_MMAPPED 0x2
-
 /* check for mmap()'ed chunk */
 #define chunk_is_mmapped(p) ((p)->mchunk_size & IS_MMAPPED)
 
-
-/* size field is or'ed with NON_MAIN_ARENA if the chunk was obtained
-   from a non-main arena.  This is only set immediately before handing
-   the chunk to the user, if necessary.  */
-#define NON_MAIN_ARENA 0x4
-
 /* Check for chunk from main arena.  */
 #define chunk_main_arena(p) (((p)->mchunk_size & NON_MAIN_ARENA) == 0)
 
 /* Mark a chunk as not being on the main arena.  */
 #define set_non_main_arena(p) ((p)->mchunk_size |= NON_MAIN_ARENA)
 
-
-/*
-   Bits to mask off when extracting size
-
-   Note: IS_MMAPPED is intentionally not masked off from size field in
-   macros for which mmapped chunks should never be seen. This should
-   cause helpful core dumps to occur if it is tried by accident by
-   people extending or adapting this malloc.
- */
-#define SIZE_BITS (PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
-
-/* Get size, ignoring use bits */
-#define chunksize(p) (chunksize_nomask (p) & ~(SIZE_BITS))
-
-/* Like chunksize, but do not mask SIZE_BITS.  */
-#define chunksize_nomask(p)         ((p)->mchunk_size)
-
 /* Ptr to next physical malloc_chunk. */
 #define next_chunk(p) ((mchunkptr) (((char *) (p)) + chunksize (p)))
 
@@ -1248,10 +1164,6 @@ checked_request2size (size_t req) __nonnull (1)
 #pragma GCC poison mchunk_size
 #pragma GCC poison mchunk_prev_size
 
-/* This is the size of the real usable data in the chunk.  Not valid for
-   dumped heap chunks.  */
-#define memsize(p) (chunksize (p) - CHUNK_HDR_SZ + SIZE_SZ)
-
 /* Huge page used for an mmap chunk.  */
 #define MMAP_HP 0x1
 
diff --git a/sysdeps/generic/malloc-chunk.h b/sysdeps/generic/malloc-chunk.h
new file mode 100644
index 0000000000..108d9e8acb
--- /dev/null
+++ b/sysdeps/generic/malloc-chunk.h
@@ -0,0 +1,70 @@
+/* Malloc chunk struct: generic version.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _GENERIC_MALLOC_CHUNK_H
+#define _GENERIC_MALLOC_CHUNK_H
+
+#include <malloc-alignment.h>
+
+/*
+  This struct declaration is misleading (but accurate and necessary).
+  It declares a "view" into memory allowing access to necessary
+  fields at known offsets from a given base. See explanation below.
+*/
+
+struct malloc_chunk {
+  INTERNAL_SIZE_T      mchunk_prev_size;  /* Size of previous chunk (if free).  */
+  INTERNAL_SIZE_T      mchunk_size;       /* Size in bytes, including overhead. */
+
+  struct malloc_chunk* fd;         /* double links -- used only if free. */
+  struct malloc_chunk* bk;
+
+  /* Only used for large blocks: pointer to next larger size.  */
+  struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
+  struct malloc_chunk* bk_nextsize;
+};
+
+/* The chunk header is two SIZE_SZ elements, but this is used widely, so
+   we define it here for clarity later.  */
+#define CHUNK_HDR_SZ (2 * SIZE_SZ)
+
+/* The smallest possible chunk */
+#define MIN_CHUNK_SIZE (offsetof(struct malloc_chunk, fd_nextsize))
+
+/* size field is or'ed with PREV_INUSE when previous adjacent chunk in use.  */
+#define PREV_INUSE 0x1
+
+/* size field is or'ed with IS_MMAPPED if the chunk was obtained with mmap() */
+#define IS_MMAPPED 0x2
+
+/* size field is or'ed with NON_MAIN_ARENA if the chunk was obtained
+   from a non-main arena.  This is only set immediately before handing
+   the chunk to the user, if necessary.  */
+#define NON_MAIN_ARENA 0x4
+
+/*
+   Bits to mask off when extracting size.
+
+   Note: IS_MMAPPED is intentionally not masked off from size field in
+   macros for which mmapped chunks should never be seen.  This should
+   cause helpful core dumps to occur if it is tried by accident by
+   people extending or adapting this malloc.
+ */
+#define SIZE_BITS (PREV_INUSE | IS_MMAPPED | NON_MAIN_ARENA)
+
+#endif /* _GENERIC_MALLOC_CHUNK_H */
diff --git a/sysdeps/generic/malloc-size.h b/sysdeps/generic/malloc-size.h
index 5b12bc9005..f72b3cfee2 100644
--- a/sysdeps/generic/malloc-size.h
+++ b/sysdeps/generic/malloc-size.h
@@ -19,6 +19,42 @@
 #ifndef _GENERIC_MALLOC_SIZE_H
 #define _GENERIC_MALLOC_SIZE_H
 
-#include <malloc-alignment.h>
+#include <malloc-chunk.h>
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+/* The smallest size we can malloc is an aligned minimal chunk.  */
+#define MINSIZE \
+  (unsigned long)(((MIN_CHUNK_SIZE + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK))
+
+/* Pad request bytes into a usable size -- internal version.  Note: This must
+   be a macro that evaluates to a compile time constant if passed a literal
+   constant.  */
+#define request2size(req)                                         \
+  (((req) + SIZE_SZ + MALLOC_ALIGN_MASK < MINSIZE)  ?             \
+   MINSIZE :                                                      \
+   ((req) + SIZE_SZ + MALLOC_ALIGN_MASK) & ~MALLOC_ALIGN_MASK)
+
+/* Check if REQ overflows when padded and aligned and if the resulting
+   value is less than PTRDIFF_T.  Returns the requested size or
+   MINSIZE in case the value is less than MINSIZE, or SIZE_MAX if any
+   of the previous checks fail.  */
+static __always_inline __attribute_maybe_unused__ size_t
+checked_request2size (size_t req) __nonnull (1)
+{
+  if (__glibc_unlikely (req > PTRDIFF_MAX))
+    return SIZE_MAX;
+  return request2size (req);
+}
+
+/* Like chunksize, but do not mask SIZE_BITS.  */
+#define chunksize_nomask(p) ((p)->mchunk_size)
+
+/* Get size, ignoring use bits.  */
+#define chunksize(p) (chunksize_nomask (p) & ~(SIZE_BITS))
+
+/* This is the size of the real usable data in the chunk.  Not valid for
+   dumped heap chunks.  */
+#define memsize(p) (chunksize (p) - CHUNK_HDR_SZ + SIZE_SZ)
 
 #endif /* _GENERIC_MALLOC_SIZE_H */