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