[PATCH v2] malloc: Cleanup _int_memalign

Adhemerval Zanella Netto adhemerval.zanella@linaro.org
Wed Oct 15 13:41:58 GMT 2025



On 09/10/25 14:37, Wilco Dijkstra wrote:
> v2: fix mmap offset on x86
> 
> 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?

Look good, some comments below.  For some reason I can not apply the patch
from patchwork, had to do manually.

> 
> ---
> 
> diff --git a/malloc/malloc.c b/malloc/malloc.c
> index 18aa546ec585f87d1a6e8358f6fbf2ba05095a44..98a38ab26b8a82aee39021143b865344c3ffab95 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;

Ok.

> 
>    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);

Ok.

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

Ok, moving the check earlier.

>      {
> -      /* 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);

Maybe:

  mchunkptr 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);
> +    }
> +
> +  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))

Maybe:

  if (!PTR_IS_ALIGNED (m, alignment))

> +    {
> +      newp = mem2chunk (((uintptr_t)m + MINSIZE + alignment - 1) & -alignment);

Maybe:

  mchunkptr newp = mem2chunk (ALIGN_UP ((uintptr_t)m + MINSIZE, alignment));


> +      size_t leadsize = (char *)newp - (char *)p;

Maybe:

  size_t leadsize = PTR_DIFF (newp, 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