|
|
|
From 265cbed8e73b23e3b38ada6cc42482c53a216224 Mon Sep 17 00:00:00 2001
|
|
|
|
From: James Lemke <jwlemke@codesourcery.com>
|
|
|
|
Date: Tue, 19 May 2015 12:10:26 -0700
|
|
|
|
Subject: [PATCH] Fix for test "malloc_usable_size: expected 7 but got 11"
|
|
|
|
|
|
|
|
[BZ #17581] The checking chain of unused chunks was terminated by a hash of
|
|
|
|
the block pointer, which was sometimes confused with the chunk length byte.
|
|
|
|
We now avoid using a length byte equal to the magic byte.
|
|
|
|
|
|
|
|
|
|
|
|
diff -rup a/malloc/hooks.c b/malloc/hooks.c
|
|
|
|
--- a/malloc/hooks.c 2017-08-01 16:19:28.000000000 -0400
|
|
|
|
+++ b/malloc/hooks.c 2017-08-01 16:42:23.651295223 -0400
|
|
|
|
@@ -87,11 +87,22 @@ __malloc_check_init()
|
|
|
|
overruns. The goal here is to avoid obscure crashes due to invalid
|
|
|
|
usage, unlike in the MALLOC_DEBUG code. */
|
|
|
|
|
|
|
|
-#define MAGICBYTE(p) ( ( ((size_t)p >> 3) ^ ((size_t)p >> 11)) & 0xFF )
|
|
|
|
+static unsigned char
|
|
|
|
+magicbyte (const void *p)
|
|
|
|
+{
|
|
|
|
+ unsigned char magic;
|
|
|
|
+
|
|
|
|
+ magic = (((uintptr_t) p >> 3) ^ ((uintptr_t) p >> 11)) & 0xFF;
|
|
|
|
+ /* Do not return 1. See the comment in mem2mem_check(). */
|
|
|
|
+ if (magic == 1)
|
|
|
|
+ ++magic;
|
|
|
|
+ return magic;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
|
|
|
|
-/* Visualize the chunk as being partitioned into blocks of 256 bytes from the
|
|
|
|
- highest address of the chunk, downwards. The beginning of each block tells
|
|
|
|
- us the size of the previous block, up to the actual size of the requested
|
|
|
|
+/* Visualize the chunk as being partitioned into blocks of 255 bytes from the
|
|
|
|
+ highest address of the chunk, downwards. The end of each block tells
|
|
|
|
+ us the size of that block, up to the actual size of the requested
|
|
|
|
memory. Our magic byte is right at the end of the requested size, so we
|
|
|
|
must reach it with this iteration, otherwise we have witnessed a memory
|
|
|
|
corruption. */
|
|
|
|
@@ -100,7 +111,7 @@ malloc_check_get_size(mchunkptr p)
|
|
|
|
{
|
|
|
|
size_t size;
|
|
|
|
unsigned char c;
|
|
|
|
- unsigned char magic = MAGICBYTE(p);
|
|
|
|
+ unsigned char magic = magicbyte (p);
|
|
|
|
|
|
|
|
assert(using_malloc_checking == 1);
|
|
|
|
|
|
|
|
@@ -120,29 +131,35 @@ malloc_check_get_size(mchunkptr p)
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Instrument a chunk with overrun detector byte(s) and convert it
|
|
|
|
- into a user pointer with requested size sz. */
|
|
|
|
+ into a user pointer with requested size req_sz. */
|
|
|
|
|
|
|
|
static void*
|
|
|
|
internal_function
|
|
|
|
-mem2mem_check(void *ptr, size_t sz)
|
|
|
|
+mem2mem_check(void *ptr, size_t req_sz)
|
|
|
|
{
|
|
|
|
mchunkptr p;
|
|
|
|
unsigned char* m_ptr = ptr;
|
|
|
|
- size_t i;
|
|
|
|
+ size_t max_sz, block_sz, i;
|
|
|
|
+ unsigned char magic;
|
|
|
|
|
|
|
|
if (!ptr)
|
|
|
|
return ptr;
|
|
|
|
p = mem2chunk(ptr);
|
|
|
|
- for(i = chunksize(p) - (chunk_is_mmapped(p) ? 2*SIZE_SZ+1 : SIZE_SZ+1);
|
|
|
|
- i > sz;
|
|
|
|
- i -= 0xFF) {
|
|
|
|
- if(i-sz < 0x100) {
|
|
|
|
- m_ptr[i] = (unsigned char)(i-sz);
|
|
|
|
- break;
|
|
|
|
+ magic = magicbyte (p);
|
|
|
|
+ max_sz = chunksize (p) - 2 * SIZE_SZ;
|
|
|
|
+ if (!chunk_is_mmapped (p))
|
|
|
|
+ max_sz += SIZE_SZ;
|
|
|
|
+ for (i = max_sz - 1; i > req_sz; i -= block_sz)
|
|
|
|
+ {
|
|
|
|
+ block_sz = MIN (i - req_sz, 0xff);
|
|
|
|
+ /* Don't allow the magic byte to appear in the chain of length bytes.
|
|
|
|
+ For the following to work, magicbyte cannot return 0x01. */
|
|
|
|
+ if (block_sz == magic)
|
|
|
|
+ --block_sz;
|
|
|
|
+
|
|
|
|
+ m_ptr[i] = block_sz;
|
|
|
|
}
|
|
|
|
- m_ptr[i] = 0xFF;
|
|
|
|
- }
|
|
|
|
- m_ptr[sz] = MAGICBYTE(p);
|
|
|
|
+ m_ptr[req_sz] = magic;
|
|
|
|
return (void*)m_ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
@@ -159,10 +176,11 @@ mem2chunk_check(void* mem, unsigned char
|
|
|
|
|
|
|
|
if(!aligned_OK(mem)) return NULL;
|
|
|
|
p = mem2chunk(mem);
|
|
|
|
+ sz = chunksize (p);
|
|
|
|
+ magic = magicbyte (p);
|
|
|
|
if (!chunk_is_mmapped(p)) {
|
|
|
|
/* Must be a chunk in conventional heap memory. */
|
|
|
|
int contig = contiguous(&main_arena);
|
|
|
|
- sz = chunksize(p);
|
|
|
|
if((contig &&
|
|
|
|
((char*)p<mp_.sbrk_base ||
|
|
|
|
((char*)p + sz)>=(mp_.sbrk_base+main_arena.system_mem) )) ||
|
|
|
|
@@ -171,9 +189,9 @@ mem2chunk_check(void* mem, unsigned char
|
|
|
|
(contig && (char*)prev_chunk(p)<mp_.sbrk_base) ||
|
|
|
|
next_chunk(prev_chunk(p))!=p) ))
|
|
|
|
return NULL;
|
|
|
|
- magic = MAGICBYTE(p);
|
|
|
|
for(sz += SIZE_SZ-1; (c = ((unsigned char*)p)[sz]) != magic; sz -= c) {
|
|
|
|
- if(c<=0 || sz<(c+2*SIZE_SZ)) return NULL;
|
|
|
|
+ if(c == 0 || sz < (c + 2 * SIZE_SZ))
|
|
|
|
+ return NULL;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
unsigned long offset, page_mask = GLRO(dl_pagesize)-1;
|
|
|
|
@@ -188,11 +206,12 @@ mem2chunk_check(void* mem, unsigned char
|
|
|
|
offset<0x2000) ||
|
|
|
|
!chunk_is_mmapped(p) || (p->size & PREV_INUSE) ||
|
|
|
|
( (((unsigned long)p - p->prev_size) & page_mask) != 0 ) ||
|
|
|
|
- ( (sz = chunksize(p)), ((p->prev_size + sz) & page_mask) != 0 ) )
|
|
|
|
+ ((p->prev_size + sz) & page_mask) != 0)
|
|
|
|
return NULL;
|
|
|
|
- magic = MAGICBYTE(p);
|
|
|
|
+
|
|
|
|
for(sz -= 1; (c = ((unsigned char*)p)[sz]) != magic; sz -= c) {
|
|
|
|
- if(c<=0 || sz<(c+2*SIZE_SZ)) return NULL;
|
|
|
|
+ if(c == 0 || sz < (c + 2 * SIZE_SZ))
|
|
|
|
+ return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
((unsigned char*)p)[sz] ^= 0xFF;
|