[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 */