public inbox for u-boot@lists.denx.de
 help / color / mirror / Atom feed
From: Sean Anderson <seanga2@gmail.com>
To: Tom Rini <trini@konsulko.com>, u-boot@lists.denx.de
Cc: Heinrich Schuchardt <xypron.glpk@gmx.de>,
	Simon Glass <sjg@chromium.org>, Sean Anderson <seanga2@gmail.com>
Subject: [PATCH v3 2/3] malloc: Annotate allocator for valgrind
Date: Wed, 23 Mar 2022 14:04:49 -0400	[thread overview]
Message-ID: <20220323180451.48950-3-seanga2@gmail.com> (raw)
In-Reply-To: <20220323180451.48950-1-seanga2@gmail.com>

This annotates malloc and friends so that valgrind can track the heap. To
do this, we need to follow a few rules:

* Call VALGRIND_MALLOCLIKE_BLOCK whenever we malloc something
* Call VALGRIND_FREELIKE_BLOCK whenever we free something (generally after
  we have done our bookkeeping)
* Call VALGRIND_RESIZEINPLACE_BLOCK whenever we change the size of an
  allocation. We don't record the original request size of a block, and
  neither does valgrind. For this reason, we pretend that the old size of
  the allocation was for 0 bytes. This marks the whole allocaton as
  undefined, so in order to mark all bits correctly, we must make the whole
  new allocation defined with VALGRIND_MAKE_MEM_DEFINED. This may cause us
  to miss some invalid reads, but there is no way to detect these without
  recording the original size of the allocation.

In addition to the above, dlmalloc itself tends to make a lot of accesses
which we know are safe, but which would be unsafe outside of dlmalloc. For
this reason, we provide a suppression file which ignores errors ocurring in
dlmalloc.c

Signed-off-by: Sean Anderson <seanga2@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
---

Changes in v3:
- Fix an additional rEALLOc branch missing VALGRIND_RESIZEINPLACE_BLOCK

Changes in v2:
- Fix one branch of rEALLOc missing a VALGRIND_*_BLOCK call
- Add some additional suppressions for cALLOc and rEALLOc
- Simplify calloc clearing logic

 common/dlmalloc.c      | 31 +++++++++++++++++++++++-
 common/malloc_simple.c | 10 ++++++++
 include/malloc.h       |  4 ++++
 scripts/u-boot.supp    | 53 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 97 insertions(+), 1 deletion(-)
 create mode 100644 scripts/u-boot.supp

diff --git a/common/dlmalloc.c b/common/dlmalloc.c
index 11729e8c85..f48cd2a333 100644
--- a/common/dlmalloc.c
+++ b/common/dlmalloc.c
@@ -18,6 +18,7 @@
 
 #include <malloc.h>
 #include <asm/io.h>
+#include <valgrind/memcheck.h>
 
 #ifdef DEBUG
 #if __STD_C
@@ -1339,6 +1340,7 @@ Void_t* mALLOc(bytes) size_t bytes;
       unlink(victim, bck, fwd);
       set_inuse_bit_at_offset(victim, victim_size);
       check_malloced_chunk(victim, nb);
+      VALGRIND_MALLOCLIKE_BLOCK(chunk2mem(victim), bytes, SIZE_SZ, false);
       return chunk2mem(victim);
     }
 
@@ -1366,6 +1368,7 @@ Void_t* mALLOc(bytes) size_t bytes;
 	unlink(victim, bck, fwd);
 	set_inuse_bit_at_offset(victim, victim_size);
 	check_malloced_chunk(victim, nb);
+        VALGRIND_MALLOCLIKE_BLOCK(chunk2mem(victim), bytes, SIZE_SZ, false);
 	return chunk2mem(victim);
       }
     }
@@ -1389,6 +1392,7 @@ Void_t* mALLOc(bytes) size_t bytes;
       set_head(remainder, remainder_size | PREV_INUSE);
       set_foot(remainder, remainder_size);
       check_malloced_chunk(victim, nb);
+      VALGRIND_MALLOCLIKE_BLOCK(chunk2mem(victim), bytes, SIZE_SZ, false);
       return chunk2mem(victim);
     }
 
@@ -1398,6 +1402,7 @@ Void_t* mALLOc(bytes) size_t bytes;
     {
       set_inuse_bit_at_offset(victim, victim_size);
       check_malloced_chunk(victim, nb);
+      VALGRIND_MALLOCLIKE_BLOCK(chunk2mem(victim), bytes, SIZE_SZ, false);
       return chunk2mem(victim);
     }
 
@@ -1453,6 +1458,7 @@ Void_t* mALLOc(bytes) size_t bytes;
 	    set_head(remainder, remainder_size | PREV_INUSE);
 	    set_foot(remainder, remainder_size);
 	    check_malloced_chunk(victim, nb);
+	    VALGRIND_MALLOCLIKE_BLOCK(chunk2mem(victim), bytes, SIZE_SZ, false);
 	    return chunk2mem(victim);
 	  }
 
@@ -1461,6 +1467,7 @@ Void_t* mALLOc(bytes) size_t bytes;
 	    set_inuse_bit_at_offset(victim, victim_size);
 	    unlink(victim, bck, fwd);
 	    check_malloced_chunk(victim, nb);
+	    VALGRIND_MALLOCLIKE_BLOCK(chunk2mem(victim), bytes, SIZE_SZ, false);
 	    return chunk2mem(victim);
 	  }
 
@@ -1509,6 +1516,7 @@ Void_t* mALLOc(bytes) size_t bytes;
     /* If big and would otherwise need to extend, try to use mmap instead */
     if ((unsigned long)nb >= (unsigned long)mmap_threshold &&
 	(victim = mmap_chunk(nb)))
+      VALGRIND_MALLOCLIKE_BLOCK(chunk2mem(victim), bytes, SIZE_SZ, false);
       return chunk2mem(victim);
 #endif
 
@@ -1523,6 +1531,7 @@ Void_t* mALLOc(bytes) size_t bytes;
   top = chunk_at_offset(victim, nb);
   set_head(top, remainder_size | PREV_INUSE);
   check_malloced_chunk(victim, nb);
+  VALGRIND_MALLOCLIKE_BLOCK(chunk2mem(victim), bytes, SIZE_SZ, false);
   return chunk2mem(victim);
 
 }
@@ -1571,8 +1580,10 @@ void fREe(mem) Void_t* mem;
 
 #if CONFIG_VAL(SYS_MALLOC_F_LEN)
 	/* free() is a no-op - all the memory will be freed on relocation */
-	if (!(gd->flags & GD_FLG_FULL_MALLOC_INIT))
+	if (!(gd->flags & GD_FLG_FULL_MALLOC_INIT)) {
+		VALGRIND_FREELIKE_BLOCK(mem, SIZE_SZ);
 		return;
+	}
 #endif
 
   if (mem == NULL)                              /* free(0) has no effect */
@@ -1594,6 +1605,7 @@ void fREe(mem) Void_t* mem;
   sz = hd & ~PREV_INUSE;
   next = chunk_at_offset(p, sz);
   nextsz = chunksize(next);
+  VALGRIND_FREELIKE_BLOCK(mem, SIZE_SZ);
 
   if (next == top)                            /* merge with top */
   {
@@ -1782,6 +1794,8 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
 	  top = chunk_at_offset(oldp, nb);
 	  set_head(top, (newsize - nb) | PREV_INUSE);
 	  set_head_size(oldp, nb);
+	  VALGRIND_RESIZEINPLACE_BLOCK(chunk2mem(oldp), 0, bytes, SIZE_SZ);
+	  VALGRIND_MAKE_MEM_DEFINED(chunk2mem(oldp), bytes);
 	  return chunk2mem(oldp);
 	}
       }
@@ -1791,6 +1805,8 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
       {
 	unlink(next, bck, fwd);
 	newsize  += nextsize;
+	VALGRIND_RESIZEINPLACE_BLOCK(chunk2mem(oldp), 0, bytes, SIZE_SZ);
+	VALGRIND_MAKE_MEM_DEFINED(chunk2mem(oldp), bytes);
 	goto split;
       }
     }
@@ -1820,10 +1836,12 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
 	    newp = prev;
 	    newsize += prevsize + nextsize;
 	    newmem = chunk2mem(newp);
+	    VALGRIND_MALLOCLIKE_BLOCK(newmem, bytes, SIZE_SZ, false);
 	    MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
 	    top = chunk_at_offset(newp, nb);
 	    set_head(top, (newsize - nb) | PREV_INUSE);
 	    set_head_size(newp, nb);
+	    VALGRIND_FREELIKE_BLOCK(oldmem, SIZE_SZ);
 	    return newmem;
 	  }
 	}
@@ -1836,6 +1854,7 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
 	  newp = prev;
 	  newsize += nextsize + prevsize;
 	  newmem = chunk2mem(newp);
+	  VALGRIND_MALLOCLIKE_BLOCK(newmem, bytes, SIZE_SZ, false);
 	  MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
 	  goto split;
 	}
@@ -1848,6 +1867,7 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
 	newp = prev;
 	newsize += prevsize;
 	newmem = chunk2mem(newp);
+	VALGRIND_MALLOCLIKE_BLOCK(newmem, bytes, SIZE_SZ, false);
 	MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
 	goto split;
       }
@@ -1874,6 +1894,9 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
     MALLOC_COPY(newmem, oldmem, oldsize - SIZE_SZ);
     fREe(oldmem);
     return newmem;
+  } else {
+    VALGRIND_RESIZEINPLACE_BLOCK(oldmem, 0, bytes, SIZE_SZ);
+    VALGRIND_MAKE_MEM_DEFINED(oldmem, bytes);
   }
 
 
@@ -1886,6 +1909,8 @@ Void_t* rEALLOc(oldmem, bytes) Void_t* oldmem; size_t bytes;
     set_head_size(newp, nb);
     set_head(remainder, remainder_size | PREV_INUSE);
     set_inuse_bit_at_offset(remainder, remainder_size);
+    VALGRIND_MALLOCLIKE_BLOCK(chunk2mem(remainder), remainder_size, SIZE_SZ,
+			      false);
     fREe(chunk2mem(remainder)); /* let free() deal with it */
   }
   else
@@ -2043,6 +2068,7 @@ Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
     set_head_size(p, leadsize);
     fREe(chunk2mem(p));
     p = newp;
+    VALGRIND_MALLOCLIKE_BLOCK(chunk2mem(p), bytes, SIZE_SZ, false);
 
     assert (newsize >= nb && (((unsigned long)(chunk2mem(p))) % alignment) == 0);
   }
@@ -2056,6 +2082,8 @@ Void_t* mEMALIGn(alignment, bytes) size_t alignment; size_t bytes;
     remainder = chunk_at_offset(p, nb);
     set_head(remainder, remainder_size | PREV_INUSE);
     set_head_size(p, nb);
+    VALGRIND_MALLOCLIKE_BLOCK(chunk2mem(remainder), remainder_size, SIZE_SZ,
+			      false);
     fREe(chunk2mem(remainder));
   }
 
@@ -2159,6 +2187,7 @@ Void_t* cALLOc(n, elem_size) size_t n; size_t elem_size;
 #endif
 
     MALLOC_ZERO(mem, csz - SIZE_SZ);
+    VALGRIND_MAKE_MEM_DEFINED(mem, sz);
     return mem;
   }
 }
diff --git a/common/malloc_simple.c b/common/malloc_simple.c
index 67ee623850..0a004d40e1 100644
--- a/common/malloc_simple.c
+++ b/common/malloc_simple.c
@@ -13,6 +13,7 @@
 #include <mapmem.h>
 #include <asm/global_data.h>
 #include <asm/io.h>
+#include <valgrind/valgrind.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -45,6 +46,7 @@ void *malloc_simple(size_t bytes)
 		return ptr;
 
 	log_debug("%lx\n", (ulong)ptr);
+	VALGRIND_MALLOCLIKE_BLOCK(ptr, bytes, 0, false);
 
 	return ptr;
 }
@@ -57,6 +59,7 @@ void *memalign_simple(size_t align, size_t bytes)
 	if (!ptr)
 		return ptr;
 	log_debug("aligned to %lx\n", (ulong)ptr);
+	VALGRIND_MALLOCLIKE_BLOCK(ptr, bytes, 0, false);
 
 	return ptr;
 }
@@ -74,6 +77,13 @@ void *calloc(size_t nmemb, size_t elem_size)
 
 	return ptr;
 }
+
+#if IS_ENABLED(CONFIG_VALGRIND)
+void free_simple(void *ptr)
+{
+	VALGRIND_FREELIKE_BLOCK(ptr, 0);
+}
+#endif
 #endif
 
 void malloc_simple_info(void)
diff --git a/include/malloc.h b/include/malloc.h
index 1fbaf3755c..e8c8b254c0 100644
--- a/include/malloc.h
+++ b/include/malloc.h
@@ -887,7 +887,11 @@ void malloc_simple_info(void);
 #define malloc malloc_simple
 #define realloc realloc_simple
 #define memalign memalign_simple
+#if IS_ENABLED(CONFIG_VALGRIND)
+#define free free_simple
+#else
 static inline void free(void *ptr) {}
+#endif
 void *calloc(size_t nmemb, size_t size);
 void *realloc_simple(void *ptr, size_t size);
 #else
diff --git a/scripts/u-boot.supp b/scripts/u-boot.supp
new file mode 100644
index 0000000000..9562b27a61
--- /dev/null
+++ b/scripts/u-boot.supp
@@ -0,0 +1,53 @@
+{
+	dlmalloc
+	Memcheck:Addr1
+	src:dlmalloc.c
+}
+{
+	dlmalloc
+	Memcheck:Addr4
+	src:dlmalloc.c
+}
+{
+	dlmalloc
+	Memcheck:Addr8
+	src:dlmalloc.c
+}
+{
+	dlmalloc
+	Memcheck:Addr1
+	fun:*
+	src:dlmalloc.c
+}
+{
+	dlmalloc
+	Memcheck:Addr4
+	fun:*
+	src:dlmalloc.c
+}
+{
+	dlmalloc
+	Memcheck:Addr8
+	fun:*
+	src:dlmalloc.c
+}
+{
+	dlmalloc
+	Memcheck:Value4
+	src:dlmalloc.c
+}
+{
+	dlmalloc
+	Memcheck:Value8
+	src:dlmalloc.c
+}
+{
+	dlmalloc
+	Memcheck:Cond
+	src:dlmalloc.c
+}
+{
+	dlmalloc
+	Memcheck:Free
+	src:dlmalloc.c
+}
-- 
2.35.1


  parent reply	other threads:[~2022-03-23 18:05 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-23 18:04 [PATCH v3 0/3] malloc: Enable profiling dlmalloc with valgrind Sean Anderson
2022-03-23 18:04 ` [PATCH v3 1/3] Add valgrind headers to U-Boot Sean Anderson
2022-04-11 14:17   ` Tom Rini
2022-03-23 18:04 ` Sean Anderson [this message]
2022-04-11 14:17   ` [PATCH v3 2/3] malloc: Annotate allocator for valgrind Tom Rini
2022-03-23 18:04 ` [PATCH v3 3/3] doc: sandbox: Document how to run sandbox with valgrind Sean Anderson
2022-04-11 14:17   ` Tom Rini
2022-03-30 18:13 ` [PATCH v3 0/3] malloc: Enable profiling dlmalloc " Sean Anderson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220323180451.48950-3-seanga2@gmail.com \
    --to=seanga2@gmail.com \
    --cc=sjg@chromium.org \
    --cc=trini@konsulko.com \
    --cc=u-boot@lists.denx.de \
    --cc=xypron.glpk@gmx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox