Added VALGRIND_MALLOCLIKE_BLOCK and VALGRIND_FREELIKE_BLOCK which allow you to
use a custom-allocator and detect almost as many errors as you could detect if
you used malloc/new/new[]. (eg. leaks detected, free errors, free mismatch,
etc).
Had to fiddle with mac_malloc_wrappers.c a bit to factor out the appropriate
code to be called from the client request handling code. Also had to add a
new element `MAC_AllocCustom' to the MAC_AllocKind type.
Also added a little documentation, and a regression test.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1643 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/memcheck/tests/custom_alloc.c b/memcheck/tests/custom_alloc.c
new file mode 100644
index 0000000..0a6ec8b
--- /dev/null
+++ b/memcheck/tests/custom_alloc.c
@@ -0,0 +1,96 @@
+#include <unistd.h>
+#include <sys/mman.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "../memcheck.h"
+
+#define SUPERBLOCK_SIZE 100000
+
+//-------------------------------------------------------------------------
+// Allocator
+//-------------------------------------------------------------------------
+
+void* get_superblock(void)
+{
+ void* p = mmap( 0, SUPERBLOCK_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_PRIVATE|MAP_ANONYMOUS, -1, 0 );
+
+ assert(p != ((void*)(-1)));
+
+ // Mark it no access; although it's addressible we don't want the
+ // program to be using it unless its handed out by custom_alloc()
+
+ // with redzones, better not to have it
+ VALGRIND_MAKE_NOACCESS(p, SUPERBLOCK_SIZE);
+
+ return p;
+}
+
+// has a redzone
+static void* custom_alloc(int size)
+{
+#define RZ 8
+ static void* hp = 0; // current heap pointer
+ static void* hp_lim = 0; // maximum usable byte in current block
+ int size2 = size + RZ*2;
+ void* p;
+
+ if (hp + size2 > hp_lim) {
+ hp = get_superblock();
+ hp_lim = hp + SUPERBLOCK_SIZE - 1;
+ }
+
+ p = hp + RZ;
+ hp += size2;
+
+ VALGRIND_MALLOCLIKE_BLOCK( p, size, RZ, /*is_zeroed*/1 );
+ return (void*)p;
+}
+
+static void custom_free(void* p)
+{
+ // don't actually free any memory... but mark it as freed
+ VALGRIND_FREELIKE_BLOCK( p, RZ );
+}
+#undef RZ
+
+
+
+//-------------------------------------------------------------------------
+// Rest
+//-------------------------------------------------------------------------
+
+void make_leak(void)
+{
+ int* array2 = custom_alloc(sizeof(int) * 10);
+ array2 = 0; // leak
+ return;
+}
+
+int main(void)
+{
+ int* array;
+ int* array3;
+
+ array = custom_alloc(sizeof(int) * 10);
+ array[8] = 8;
+ array[9] = 8;
+ array[10] = 10; // invalid write (ok w/o MALLOCLIKE -- in superblock)
+
+ custom_free(array); // ok
+
+ custom_free(NULL); // invalid free (ok without MALLOCLIKE)
+
+ array3 = malloc(sizeof(int) * 10);
+ custom_free(array3); // mismatched free (ok without MALLOCLIKE)
+
+ make_leak();
+ return array[0]; // use after free (ok without MALLOCLIKE/MAKE_NOACCESS)
+ // (nb: initialised because is_zeroed==1 above)
+ // unfortunately not identified as being in a free'd
+ // block because the freeing of the block and shadow
+ // chunk isn't postponed.
+
+ // leak from make_leak()
+}