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