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