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