[PATCH 2/2] malloc: Cleanup _int_memalign
Wilco Dijkstra
Wilco.Dijkstra@arm.com
Thu Oct 2 16:27:16 GMT 2025
Cleanup _int_memalign. Simplify the logic. Add a seperate check
for mmap. Only release the tail chunk if it is at least MINSIZE.
Use the new mmap abstractions.
Passes regress, OK for commit?
---
diff --git a/malloc/malloc.c b/malloc/malloc.c
index ac85d7e2366d49238b732139f2540839ab6185af..6907b3f23b86e76a523e0d1df9735a1e9bc2cbea 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -5166,107 +5166,64 @@ _int_realloc (mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
------------------------------ memalign ------------------------------
*/
-/* BYTES is user requested bytes, not requested chunksize bytes. */
+/* BYTES is user requested bytes, not requested chunksize bytes.
+ ALIGNMENT is a power of 2 larger than or equal to MINSIZE. */
static void *
_int_memalign (mstate av, size_t alignment, size_t bytes)
{
- INTERNAL_SIZE_T nb; /* padded request size */
- char *m; /* memory returned by malloc call */
- mchunkptr p; /* corresponding chunk */
- char *brk; /* alignment point within p */
- mchunkptr newp; /* chunk to return */
- INTERNAL_SIZE_T newsize; /* its size */
- INTERNAL_SIZE_T leadsize; /* leading space before alignment point */
- mchunkptr remainder; /* spare room at end to split off */
- unsigned long remainder_size; /* its size */
- INTERNAL_SIZE_T size;
+ mchunkptr p, newp;
if (bytes > PTRDIFF_MAX)
{
__set_errno (ENOMEM);
return NULL;
}
- nb = checked_request2size (bytes);
-
- /* We can't check tcache here because we hold the arena lock, which
- tcache doesn't expect. We expect it has been checked
- earlier. */
-
- /* Strategy: search the bins looking for an existing block that
- meets our needs. We scan a range of bins from "exact size" to
- "just under 2x", spanning the small/large barrier if needed. If
- we don't find anything in those bins, the common malloc code will
- scan starting at 2x. */
+ size_t nb = checked_request2size (bytes);
/* Call malloc with worst case padding to hit alignment. */
- m = (char *) (_int_malloc (av, nb + alignment + MINSIZE));
+ char *m = (char *) (_int_malloc (av, nb + alignment + MINSIZE));
if (m == NULL)
- return NULL; /* propagate failure */
+ return NULL;
p = mem2chunk (m);
- if ((((unsigned long) (m)) % alignment) != 0) /* misaligned */
+ if (chunk_is_mmapped (p))
{
- /* Find an aligned spot inside chunk. Since we need to give back
- leading space in a chunk of at least MINSIZE, if the first
- calculation places us at a spot with less than MINSIZE leader,
- we can move to the next aligned spot -- we've allocated enough
- total room so that this is always possible. */
- brk = (char *) mem2chunk (((unsigned long) (m + alignment - 1)) &
- - ((signed long) alignment));
- if ((unsigned long) (brk - (char *) (p)) < MINSIZE)
- brk += alignment;
-
- newp = (mchunkptr) brk;
- leadsize = brk - (char *) (p);
- newsize = chunksize (p) - leadsize;
-
- /* For mmapped chunks, just adjust offset */
- if (chunk_is_mmapped (p))
- {
- set_prev_size (newp, prev_size (p) + leadsize);
- set_head (newp, newsize | IS_MMAPPED);
- return chunk2mem (newp);
- }
+ newp = mem2chunk (((uintptr_t)m + alignment - 1) & -alignment);
+ p = mmap_set_chunk (mmap_base (p), mmap_size (p),
+ (char *)newp - (char *)p, mmap_is_hp (p));
+ return chunk2mem (p);
+ }
+
+ size_t size = chunksize (p);
+
+ /* If not already aligned, align the chunk. Always add MINSIZE before
+ aligning so we can free the chunk before the aligned chunk. */
+ if ((uintptr_t)m & (alignment - 1))
+ {
+ newp = mem2chunk (((uintptr_t)m + MINSIZE + alignment - 1) & -alignment);
+ size_t leadsize = (char *)newp - (char *)p;
+ size -= leadsize;
/* Otherwise, give back leader, use the rest */
- set_head (newp, newsize | PREV_INUSE |
- (av != &main_arena ? NON_MAIN_ARENA : 0));
- set_inuse_bit_at_offset (newp, newsize);
- set_head_size (p, leadsize | (av != &main_arena ? NON_MAIN_ARENA : 0));
+ int arena_flag = av != &main_arena ? NON_MAIN_ARENA : 0;
+ set_head (newp, size | PREV_INUSE | arena_flag);
+ set_inuse_bit_at_offset (newp, size);
+ set_head_size (p, leadsize | arena_flag);
_int_free_merge_chunk (av, p, leadsize);
p = newp;
-
- assert (newsize >= nb &&
- (((unsigned long) (chunk2mem (p))) % alignment) == 0);
}
- /* Also give back spare room at the end */
- if (!chunk_is_mmapped (p))
+ /* Free a chunk at the end if large enough. */
+ if (size - nb >= MINSIZE)
{
- size = chunksize (p);
- mchunkptr nextchunk = chunk_at_offset(p, size);
- INTERNAL_SIZE_T nextsize = chunksize(nextchunk);
- if (size > nb)
- {
- remainder_size = size - nb;
- if (remainder_size >= MINSIZE
- || nextchunk == av->top
- || !inuse_bit_at_offset (nextchunk, nextsize))
- {
- /* We can only give back the tail if it is larger than
- MINSIZE, or if the following chunk is unused (top
- chunk or unused in-heap chunk). Otherwise we would
- create a chunk that is smaller than MINSIZE. */
- remainder = chunk_at_offset (p, nb);
- set_head_size (p, nb);
- remainder_size = _int_free_create_chunk (av, remainder,
- remainder_size,
- nextchunk, nextsize);
- _int_free_maybe_consolidate (av, remainder_size);
- }
- }
+ mchunkptr nextchunk = chunk_at_offset (p, size);
+ mchunkptr remainder = chunk_at_offset (p, nb);
+ set_head_size (p, nb);
+ size = _int_free_create_chunk (av, remainder, size - nb, nextchunk,
+ chunksize (nextchunk));
+ _int_free_maybe_consolidate (av, size);
}
check_inuse_chunk (av, p);
More information about the Libc-alpha
mailing list