This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
PATCH: Make chunk size a multiple of MALLOC_ALIGNMENT
- From: "H.J. Lu" <hongjiu dot lu at intel dot com>
- To: GNU C Library <libc-alpha at sourceware dot org>
- Date: Thu, 24 May 2012 12:30:00 -0700
- Subject: PATCH: Make chunk size a multiple of MALLOC_ALIGNMENT
- Reply-to: "H.J. Lu" <hjl dot tools at gmail dot com>
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.
However, when sysmalloc frees old top chunk with size >= MINSIZE, it
doesn't make sure that the size is a multiple of MALLOC_ALIGNMENT:
/* 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?
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. */
/* 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;
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. */
+ if (__builtin_expect (size < MINSIZE
+ || (size & MALLOC_ALIGN_MASK) != 0, 0))
{
errstr = "free(): invalid size";
goto errout;
--
1.7.6.5