misc: address sanitizer: do not instrument dlmalloc internals
[vpp.git] / src / vppinfra / dlmalloc.c
index 8ae92cf..23b4dfc 100644 (file)
@@ -6,6 +6,7 @@
 */
 
 #include <vppinfra/dlmalloc.h>
+#include <vppinfra/sanitizer.h>
 
 /*------------------------------ internal #includes ---------------------- */
 
@@ -342,7 +343,7 @@ static FORCEINLINE int win32munmap(void* ptr, size_t size) {
     #define CALL_MREMAP(addr, osz, nsz, mv)     MFAIL
 #endif /* HAVE_MMAP && HAVE_MREMAP */
 
-/* mstate bit set if continguous morecore disabled or failed */
+/* mstate bit set if contiguous morecore disabled or failed */
 #define USE_NONCONTIGUOUS_BIT (4U)
 
 /* mstate bit set if no expansion allowed */
@@ -459,6 +460,7 @@ static FORCEINLINE void x86_clear_lock(int* sl) {
 
 #if !defined(USE_RECURSIVE_LOCKS) || USE_RECURSIVE_LOCKS == 0
 /* Plain spin locks use single word (embedded in malloc_states) */
+CLIB_NOSANITIZE_ADDR
 static int spin_acquire_lock(int *sl) {
   int spins = 0;
   while (*(volatile int *)sl != 0 || CAS_LOCK(sl)) {
@@ -1284,6 +1286,7 @@ static struct malloc_state _gm_;
   ((char*)(A) >= S->base && (char*)(A) < S->base + S->size)
 
 /* Return segment holding given address */
+CLIB_NOSANITIZE_ADDR
 static msegmentptr segment_holding(mstate m, char* addr) {
   msegmentptr sp = &m->seg;
   for (;;) {
@@ -1295,6 +1298,7 @@ static msegmentptr segment_holding(mstate m, char* addr) {
 }
 
 /* Return true if segment contains a segment link */
+CLIB_NOSANITIZE_ADDR
 static int has_segment_link(mstate m, msegmentptr ss) {
   msegmentptr sp = &m->seg;
   for (;;) {
@@ -1585,7 +1589,7 @@ static size_t traverse_and_check(mstate m);
   http://www.usenix.org/events/lisa03/tech/robertson.html The footer
   of an inuse chunk holds the xor of its mstate and a random seed,
   that is checked upon calls to free() and realloc().  This is
-  (probabalistically) unguessable from outside the program, but can be
+  (probabilistically) unguessable from outside the program, but can be
   computed by any code successfully malloc'ing any chunk, so does not
   itself provide protection against code that has already broken
   security through some other means.  Unlike Robertson et al, we
@@ -1612,7 +1616,12 @@ static size_t traverse_and_check(mstate m);
 
 #if (FOOTERS && !INSECURE)
 /* Check if (alleged) mstate m has expected magic field */
-#define ok_magic(M)      ((M)->magic == mparams.magic)
+CLIB_NOSANITIZE_ADDR
+static inline int
+ok_magic (const mstate m)
+{
+    return (m->magic == mparams.magic);
+}
 #else  /* (FOOTERS && !INSECURE) */
 #define ok_magic(M)      (1)
 #endif /* (FOOTERS && !INSECURE) */
@@ -2074,8 +2083,9 @@ static void do_check_malloc_state(mstate m) {
 /* ----------------------------- statistics ------------------------------ */
 
 #if !NO_MALLINFO
-static struct mallinfo internal_mallinfo(mstate m) {
-  struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+CLIB_NOSANITIZE_ADDR
+static struct dlmallinfo internal_mallinfo(mstate m) {
+  struct dlmallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
   ensure_initialization();
   if (!PREACTION(m)) {
     check_malloc_state(m);
@@ -2483,6 +2493,7 @@ static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb, int flags) {
 /* -------------------------- mspace management -------------------------- */
 
 /* Initialize top chunk and its size */
+CLIB_NOSANITIZE_ADDR
 static void init_top(mstate m, mchunkptr p, size_t psize) {
   /* Ensure alignment */
   size_t offset = align_offset(chunk2mem(p));
@@ -2527,6 +2538,7 @@ static void reset_on_error(mstate m) {
 #endif /* PROCEED_ON_ERROR */
 
 /* Allocate chunk and prepend remainder with chunk in successor base. */
+CLIB_NOSANITIZE_ADDR
 static void* prepend_alloc(mstate m, char* newbase, char* oldbase,
                            size_t nb) {
   mchunkptr p = align_as_chunk(newbase);
@@ -2569,6 +2581,7 @@ static void* prepend_alloc(mstate m, char* newbase, char* oldbase,
 }
 
 /* Add a segment to hold a new noncontiguous region */
+CLIB_NOSANITIZE_ADDR
 static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) {
   /* Determine locations and sizes of segment, fenceposts, old top */
   char* old_top = (char*)m->top;
@@ -2624,6 +2637,7 @@ static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) {
 /* -------------------------- System allocation -------------------------- */
 
 /* Get memory from system using MORECORE or MMAP */
+CLIB_NOSANITIZE_ADDR
 static void* sys_alloc(mstate m, size_t nb) {
   char* tbase = CMFAIL;
   size_t tsize = 0;
@@ -2838,6 +2852,7 @@ static void* sys_alloc(mstate m, size_t nb) {
 /* -----------------------  system deallocation -------------------------- */
 
 /* Unmap and unlink any mmapped segments that don't contain used chunks */
+CLIB_NOSANITIZE_ADDR
 static size_t release_unused_segments(mstate m) {
   size_t released = 0;
   int nsegs = 0;
@@ -2885,6 +2900,7 @@ static size_t release_unused_segments(mstate m) {
   return released;
 }
 
+CLIB_NOSANITIZE_ADDR
 static int sys_trim(mstate m, size_t pad) {
   size_t released = 0;
   ensure_initialization();
@@ -2953,6 +2969,7 @@ static int sys_trim(mstate m, size_t pad) {
 /* Consolidate and bin a chunk. Differs from exported versions
    of free mainly in that the chunk need not be marked as inuse.
 */
+CLIB_NOSANITIZE_ADDR
 static void dispose_chunk(mstate m, mchunkptr p, size_t psize) {
   mchunkptr next = chunk_plus_offset(p, psize);
   if (!pinuse(p)) {
@@ -3024,6 +3041,7 @@ static void dispose_chunk(mstate m, mchunkptr p, size_t psize) {
 /* ---------------------------- malloc --------------------------- */
 
 /* allocate a large request from the best fitting chunk in a treebin */
+CLIB_NOSANITIZE_ADDR
 static void* tmalloc_large(mstate m, size_t nb) {
   tchunkptr v = 0;
   size_t rsize = -nb; /* Unsigned negation */
@@ -3095,6 +3113,7 @@ static void* tmalloc_large(mstate m, size_t nb) {
 }
 
 /* allocate a small request from the best fitting chunk in a treebin */
+CLIB_NOSANITIZE_ADDR
 static void* tmalloc_small(mstate m, size_t nb) {
   tchunkptr t, v;
   size_t rsize;
@@ -3274,7 +3293,7 @@ void* dlmalloc(size_t bytes) {
 
 void dlfree(void* mem) {
   /*
-     Consolidate freed chunks with preceeding or succeeding bordering
+     Consolidate freed chunks with preceding or succeeding bordering
      free chunks, if they exist, and then place in a bin.  Intermixed
      with special cases for top, dv, mmapped chunks, and usage errors.
   */
@@ -3480,6 +3499,7 @@ static mchunkptr try_realloc_chunk(mstate m, mchunkptr p, size_t nb,
   return newp;
 }
 
+CLIB_NOSANITIZE_ADDR
 static void* internal_memalign(mstate m, size_t alignment, size_t bytes) {
   void* mem = 0;
   if (alignment <  MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */
@@ -3959,7 +3979,7 @@ size_t dlmalloc_set_footprint_limit(size_t bytes) {
 }
 
 #if !NO_MALLINFO
-struct mallinfo dlmallinfo(void) {
+struct dlmallinfo dlmallinfo(void) {
   return internal_mallinfo(gm);
 }
 #endif /* NO_MALLINFO */
@@ -4085,19 +4105,19 @@ size_t destroy_mspace(mspace msp) {
   return freed;
 }
 
-void mspace_get_address_and_size (mspace msp, unsigned long long *addrp,
-                                  unsigned long long *sizep)
+void mspace_get_address_and_size (mspace msp, char **addrp, size_t *sizep)
 {
   mstate ms;
   msegment *this_seg;
-  
+
   ms = (mstate)msp;
   this_seg = &ms->seg;
 
-  *addrp = (unsigned long long) this_seg->base;
+  *addrp = this_seg->base;
   *sizep = this_seg->size;
 }
 
+CLIB_NOSANITIZE_ADDR
 int mspace_is_heap_object (mspace msp, void *p)
 {
   msegment *this_seg;
@@ -4116,9 +4136,14 @@ int mspace_is_heap_object (mspace msp, void *p)
         return 1;
       this_seg = this_seg->next;
     }
+
+  if (pp > ms->least_addr && pp <= ms->least_addr + ms->footprint)
+    return 1;
+
   return 0;
 }
 
+CLIB_NOSANITIZE_ADDR
 void *mspace_least_addr (mspace msp)
 {
   mstate ms = (mstate) msp;
@@ -4132,6 +4157,7 @@ void mspace_disable_expand (mspace msp)
   disable_expand (ms);
 }
 
+CLIB_NOSANITIZE_ADDR
 int mspace_enable_disable_trace (mspace msp, int enable)
 {
   mstate ms = (mstate)msp;
@@ -4148,25 +4174,36 @@ int mspace_enable_disable_trace (mspace msp, int enable)
   return (was_enabled);
 }
 
-void* mspace_get_aligned (mspace msp, 
-                          unsigned long long n_user_data_bytes,
-                          unsigned long long align, 
-                          unsigned long long align_offset) {
+CLIB_NOSANITIZE_ADDR
+int mspace_is_traced (mspace msp)
+{
+  mstate ms = (mstate)msp;
+
+  if (use_trace(ms))
+    return 1;
+  return 0;
+}
+
+CLIB_NOSANITIZE_ADDR
+void* mspace_get_aligned (mspace msp,
+                          unsigned long n_user_data_bytes,
+                          unsigned long align,
+                          unsigned long align_offset) {
   char *rv;
-  unsigned long long searchp;
+  unsigned long searchp;
   unsigned *wwp;                /* "where's Waldo" pointer */
   mstate ms = (mstate)msp;
 
   /*
-   * Allocate space for the "Where's Waldo?" pointer 
+   * Allocate space for the "Where's Waldo?" pointer
    * the base of the dlmalloc object
    */
   n_user_data_bytes += sizeof(unsigned);
 
-  /* 
-   * Alignment requests less than the size of an mmx vector are ignored 
+  /*
+   * Alignment requests less than the size of an mmx vector are ignored
    */
-  if (align < 16) {
+  if (align < sizeof (uword)) {
     rv = mspace_malloc (msp, n_user_data_bytes);
     if (rv == 0)
         return rv;
@@ -4174,8 +4211,8 @@ void* mspace_get_aligned (mspace msp,
     if (use_trace(ms)) {
       mchunkptr p  = mem2chunk(rv);
       size_t psize = chunksize(p);
-      
-      mheap_get_trace ((u64)rv + sizeof (unsigned), psize);
+
+      mheap_get_trace ((unsigned long)rv + sizeof (unsigned), psize);
     }
 
     wwp = (unsigned *)rv;
@@ -4189,20 +4226,20 @@ void* mspace_get_aligned (mspace msp,
    * Alignment requests greater than 4K must be at offset zero,
    * and must be freed using mspace_free_no_offset - or never freed -
    * since the "Where's Waldo?" pointer would waste too much space.
-   * 
-   * Waldo is the address of the chunk of memory returned by mspace_malloc, 
+   *
+   * Waldo is the address of the chunk of memory returned by mspace_malloc,
    * which we need later to call mspace_free...
    */
-  if (align > 4<<10 || align_offset == ~0ULL) {
+  if (align > 4<<10 || align_offset == ~0UL) {
     n_user_data_bytes -= sizeof(unsigned);
     assert(align_offset == 0);
     rv = internal_memalign(ms, (size_t)align, n_user_data_bytes);
-    
+
     /* Trace the allocation */
     if (rv && use_trace(ms)) {
       mchunkptr p  = mem2chunk(rv);
       size_t psize = chunksize(p);
-      mheap_get_trace ((u64)rv, psize);
+      mheap_get_trace ((unsigned long)rv, psize);
     }
     return rv;
   }
@@ -4220,7 +4257,7 @@ void* mspace_get_aligned (mspace msp,
       return rv;
 
   /* Honor the alignment request */
-  searchp = (unsigned long long)(rv + sizeof (unsigned));
+  searchp = (unsigned long)(rv + sizeof (unsigned));
 
 #if 0  /* this is the idea... */
   while ((searchp + align_offset) % align)
@@ -4228,7 +4265,7 @@ void* mspace_get_aligned (mspace msp,
 #endif
 
   {
-    unsigned long long where_now, delta;
+    unsigned long where_now, delta;
 
     where_now = (searchp + align_offset) % align;
     delta = align - where_now;
@@ -4237,17 +4274,18 @@ void* mspace_get_aligned (mspace msp,
   }
 
   wwp = (unsigned *)(searchp - sizeof(unsigned));
-  *wwp = (searchp - (((unsigned long long) rv) + sizeof (*wwp)));
+  *wwp = (searchp - (((unsigned long) rv) + sizeof (*wwp)));
   assert (*wwp < align);
 
   if (use_trace(ms)) {
     mchunkptr p  = mem2chunk(rv);
     size_t psize = chunksize(p);
-    mheap_get_trace ((u64)rv, psize);
+    mheap_get_trace (searchp, psize);
   }
   return (void *) searchp;
 }
 
+CLIB_NOSANITIZE_ADDR
 void mspace_put (mspace msp, void *p_arg)
 {
   char *object_header;
@@ -4268,9 +4306,17 @@ void mspace_put (mspace msp, void *p_arg)
       mchunkptr p  = mem2chunk(object_header);
       size_t psize = chunksize(p);
 
-      mheap_put_trace ((u64)p_arg, psize);
+      mheap_put_trace ((unsigned long)p_arg, psize);
     }
 
+#if CLIB_DEBUG > 0 && !defined(CLIB_SANITIZE_ADDR)
+  /* Poison the object */
+  {
+    size_t psize = mspace_usable_size (object_header);
+    memset (object_header, 0x13, psize);
+  }
+#endif
+
   /* And free it... */
   mspace_free (msp, object_header);
 }
@@ -4284,11 +4330,12 @@ void mspace_put_no_offset (mspace msp, void *p_arg)
       mchunkptr p  = mem2chunk(p_arg);
       size_t psize = chunksize(p);
 
-      mheap_put_trace ((u64)p_arg, psize);
+      mheap_put_trace ((unsigned long)p_arg, psize);
     }
   mspace_free (msp, p_arg);
 }
 
+CLIB_NOSANITIZE_ADDR
 size_t mspace_usable_size_with_delta (const void *p)
 {
   size_t usable_size;
@@ -4314,6 +4361,7 @@ size_t mspace_usable_size_with_delta (const void *p)
   versions. This is not so nice but better than the alternatives.
 */
 
+CLIB_NOSANITIZE_ADDR
 void* mspace_malloc(mspace msp, size_t bytes) {
   mstate ms = (mstate)msp;
   if (!ok_magic(ms)) {
@@ -4428,6 +4476,7 @@ void* mspace_malloc(mspace msp, size_t bytes) {
   return 0;
 }
 
+CLIB_NOSANITIZE_ADDR
 void mspace_free(mspace msp, void* mem) {
   if (mem != 0) {
     mchunkptr p  = mem2chunk(mem);
@@ -4765,7 +4814,8 @@ size_t mspace_set_footprint_limit(mspace msp, size_t bytes) {
 }
 
 #if !NO_MALLINFO
-struct mallinfo mspace_mallinfo(mspace msp) {
+CLIB_NOSANITIZE_ADDR
+struct dlmallinfo mspace_mallinfo(mspace msp) {
   mstate ms = (mstate)msp;
   if (!ok_magic(ms)) {
     USAGE_ERROR_ACTION(ms,ms);
@@ -4774,6 +4824,7 @@ struct mallinfo mspace_mallinfo(mspace msp) {
 }
 #endif /* NO_MALLINFO */
 
+CLIB_NOSANITIZE_ADDR
 size_t mspace_usable_size(const void* mem) {
   if (mem != 0) {
     mchunkptr p = mem2chunk(mem);
@@ -5032,10 +5083,10 @@ History:
         Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
       * Use last_remainder in more cases.
       * Pack bins using idea from  colin@nyx10.cs.du.edu
-      * Use ordered bins instead of best-fit threshhold
+      * Use ordered bins instead of best-fit threshold
       * Eliminate block-local decls to simplify tracing and debugging.
       * Support another case of realloc via move into top
-      * Fix error occuring when initial sbrk_base not word-aligned.
+      * Fix error occurring when initial sbrk_base not word-aligned.
       * Rely on page size for units instead of SBRK_UNIT to
         avoid surprises about sbrk alignment conventions.
       * Add mallinfo, mallopt. Thanks to Raymond Nijssen