[PATCH v3] malloc: Cleanup _int_memalign
Adhemerval Zanella Netto
adhemerval.zanella@linaro.org
Fri Oct 17 16:28:17 GMT 2025
On 15/10/25 15:40, Wilco Dijkstra wrote:
> v3: Use PTR_ALIGN_UP/PTR_DIFF/PTR_IS_ALIGNED as suggested.
> Use void* for m. Cleanup comments. Rebase to trunk.
>
> 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?
LGTM, thanks.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
>
> ---
>
> diff --git a/malloc/malloc.c b/malloc/malloc.c
> index 18aa546ec585f87d1a6e8358f6fbf2ba05095a44..b79582a680a359f398c02060e14a7dafa704be70 100644
> --- a/malloc/malloc.c
> +++ b/malloc/malloc.c
> @@ -5101,107 +5101,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));
> + /* Call malloc with worst case padding to hit alignment. */
> + void *m = _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 (PTR_ALIGN_UP (m, alignment));
> + p = mmap_set_chunk (mmap_base (p), mmap_size (p),
> + (uintptr_t)newp - mmap_base (p), mmap_is_hp (p));
> + return chunk2mem (p);
> + }
>
> - /* 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));
> + size_t size = chunksize (p);
> +
> + /* If not already aligned, align the chunk. Add MINSIZE before aligning
> + so we can always free the alignment padding. */
> + if (!PTR_IS_ALIGNED (m, alignment))
> + {
> + newp = mem2chunk (ALIGN_UP ((uintptr_t)m + MINSIZE, alignment));
> + size_t leadsize = PTR_DIFF (newp, p);
> + size -= leadsize;
> +
> + /* Create a new chunk from the alignment padding and free it. */
> + 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