You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
138 lines
4.6 KiB
138 lines
4.6 KiB
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;
|
|
|