PATCH: Make chunk size a multiple of MALLOC_ALIGNMENT

Carlos O'Donell carlos@systemhalted.org
Fri May 25 00:12:00 GMT 2012


On Thu, May 24, 2012 at 3:30 PM, H.J. Lu <hongjiu.lu@intel.com> wrote:
> Hi,
>
> do_check_free_chunk has
>
> static void do_check_free_chunk(mstate av, mchunkptr p)
> {
>  INTERNAL_SIZE_T sz = p->size & ~(PREV_INUSE|NON_MAIN_ARENA);
>  mchunkptr next = chunk_at_offset(p, sz);
>
>  do_check_chunk(av, p);
>
>  /* Chunk must claim to be free ... */
>  assert(!inuse(p));
>  assert (!chunk_is_mmapped(p));
>
>  /* Unless a special marker, must have OK fields */
>  if ((unsigned long)(sz) >= MINSIZE)
>  {
>    assert((sz & MALLOC_ALIGN_MASK) == 0);
>
> If a free chunk >= MINSIZE, it must be a multiple of MALLOC_ALIGNMENT.

Agreed.

> However, when sysmalloc frees old top chunk with size >= MINSIZE, it
> doesn't make sure that the size is a multiple of MALLOC_ALIGNMENT:

Agreed.

>     /* Setup fencepost and free the old top chunk. */
>      /* The fencepost takes at least MINSIZE bytes, because it might
>         become the top chunk again later.  Note that a footer is set
>         up, too, although the chunk is marked in use. */
>      old_size -= MINSIZE;
>      set_head(chunk_at_offset(old_top, old_size + 2*SIZE_SZ), 0|PREV_INUSE);
>      if (old_size >= MINSIZE) {
>        set_head(chunk_at_offset(old_top, old_size), (2*SIZE_SZ)|PREV_INUSE);
>        set_foot(chunk_at_offset(old_top, old_size), (2*SIZE_SZ));
>        set_head(old_top, old_size|PREV_INUSE|NON_MAIN_ARENA);
>        _int_free(av, old_top, 1);
>      } else {
>
> This bug caused some test failures in one of nss packages on Linux/x32.
> This patch fixes it.  OK to install?

Why doesn't this trigger for any other architectures?

> Thanks.
>
>
> H.J.
> ---
>        [BZ #13576]
>        * malloc/malloc.c (sYSMALLOc): Free the old top chunk with a
>        multiple of MALLOC_ALIGNMENT in size.
>        (_int_free): Check chunk size is a multiple of MALLOC_ALIGNMENT.
>
> diff --git a/malloc/malloc.c b/malloc/malloc.c
> index bb26937..46826ab 100644
> --- a/malloc/malloc.c
> +++ b/malloc/malloc.c
> @@ -2390,11 +2390,12 @@ static void* sysmalloc(INTERNAL_SIZE_T nb, mstate av)
>       top(av) = chunk_at_offset(heap, sizeof(*heap));
>       set_head(top(av), (heap->size - sizeof(*heap)) | PREV_INUSE);
>
> -      /* Setup fencepost and free the old top chunk. */
> +      /* Setup fencepost and free the old top chunk with a multiple of
> +        MALLOC_ALIGNMENT in size. */

OK.

>       /* The fencepost takes at least MINSIZE bytes, because it might
>         become the top chunk again later.  Note that a footer is set
>         up, too, although the chunk is marked in use. */
> -      old_size -= MINSIZE;
> +      old_size = (old_size - MINSIZE) & ~MALLOC_ALIGN_MASK;

OK.

>       set_head(chunk_at_offset(old_top, old_size + 2*SIZE_SZ), 0|PREV_INUSE);
>       if (old_size >= MINSIZE) {
>        set_head(chunk_at_offset(old_top, old_size), (2*SIZE_SZ)|PREV_INUSE);
> @@ -3803,8 +3804,10 @@ _int_free(mstate av, mchunkptr p, int have_lock)
>       malloc_printerr (check_action, errstr, chunk2mem(p));
>       return;
>     }
> -  /* We know that each chunk is at least MINSIZE bytes in size.  */
> -  if (__builtin_expect (size < MINSIZE, 0))
> +  /* We know that each chunk is at least MINSIZE bytes in size of a
> +     multiple of MALLOC_ALIGNMENT.  */

Should e "or a" not "of a"?

> +  if (__builtin_expect (size < MINSIZE
> +                       || (size & MALLOC_ALIGN_MASK) != 0, 0))

Should this use aligned_OK?

The aligned_OK macro should be used in a lot more places :-(

>     {
>       errstr = "free(): invalid size";
>       goto errout;
> --
> 1.7.6.5
>

Cheers,
Carlos.



More information about the Libc-alpha mailing list