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()
+}