Fix for bug #78048.

Problem was that the malloc-replacing tools (memcheck, addrcheck, massif,
helgrind) would assert if a too-big malloc was attempted.  Now they return 0 to
the client.  I also cleaned up the code handling heap-block-metadata in Massif
and Addrcheck/Memcheck a little.

This exposed a nasty bug in VG_(client_alloc)() which wasn't checking if
find_map_space() was succeeding before attempting an mmap().  Before I added
the check, very big mallocs (eg 2GB) for Addrcheck were overwriting the client
space at address 0 and causing crashes.

Added a regtest to all the affected skins for this.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2462 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/massif/ms_main.c b/massif/ms_main.c
index 44b865a..7d8a357 100644
--- a/massif/ms_main.c
+++ b/massif/ms_main.c
@@ -664,49 +664,42 @@
 static void hp_census(void);
 
 static __inline__
-void new_block_meta ( void* p, Int size, Bool custom_malloc )
+void* new_block ( void* p, Int size, UInt align, Bool is_zeroed )
 {
    HP_Chunk* hc;
-
-   VGP_PUSHCC(VgpCliMalloc);
-
-   if (0 == size) n_zero_allocs++;
-   
-   // Make new HP_Chunk node, add to malloclist
-   hc       = VG_(malloc)(sizeof(HP_Chunk));
-   hc->size = size;
-   hc->data = (Addr)p;
-
-   if (clo_heap) {
-      hc->where = get_XCon( VG_(get_current_or_recent_tid)(), custom_malloc );
-      if (size != 0) 
-         update_XCon(hc->where, size);
-   } else {
-      hc->where = NULL;    // paranoia
-   }
-
-   add_HP_Chunk( hc );
-
-   hp_census();      // do a census!
-
-   VGP_POPCC(VgpCliMalloc);
-}
-
-static __inline__
-void* new_block ( Int size, UInt align, Bool is_zeroed )
-{
-   void* p;
-
+   Bool custom_alloc = (NULL == p);
    if (size < 0) return NULL;
 
    VGP_PUSHCC(VgpCliMalloc);
 
    // Update statistics
    n_allocs++;
+   if (0 == size) n_zero_allocs++;
 
-   p = VG_(cli_malloc)( align, size );
-   if (is_zeroed) VG_(memset)(p, 0, size);
-   new_block_meta(p, size, /*custom_malloc*/False);
+   // Allocate and zero if necessary
+   if (!p) {
+      p = VG_(cli_malloc)( align, size );
+      if (!p) {
+         VGP_POPCC(VgpCliMalloc);
+         return NULL;
+      }
+      if (is_zeroed) VG_(memset)(p, 0, size);
+   }
+
+   // Make new HP_Chunk node, add to malloclist
+   hc       = VG_(malloc)(sizeof(HP_Chunk));
+   hc->size = size;
+   hc->data = (Addr)p;
+   hc->where = NULL;    // paranoia
+   if (clo_heap) {
+      hc->where = get_XCon( VG_(get_current_or_recent_tid)(), custom_alloc );
+      if (0 != size) 
+         update_XCon(hc->where, size);
+   }
+   add_HP_Chunk( hc );
+
+   // do a census!
+   hp_census();      
 
    VGP_POPCC(VgpCliMalloc);
    return p;
@@ -715,60 +708,59 @@
 static __inline__
 void die_block ( void* p, Bool custom_free )
 {
-   HP_Chunk*  hc;
-   HP_Chunk** remove_handle;
+   HP_Chunk *hc, **remove_handle;
    
    VGP_PUSHCC(VgpCliMalloc);
 
    // Update statistics
    n_frees++;
 
-   hc = get_HP_Chunk ( p, &remove_handle );
+   // Remove HP_Chunk from malloclist
+   hc = get_HP_Chunk( p, &remove_handle );
    if (hc == NULL)
       return;   // must have been a bogus free(), or p==NULL
-
    sk_assert(hc->data == (Addr)p);
+   remove_HP_Chunk(hc, remove_handle);
 
    if (clo_heap && hc->size != 0)
       update_XCon(hc->where, -hc->size);
 
-   // Actually free the heap block
+   VG_(free)( hc );
+
+   // Actually free the heap block, if necessary
    if (!custom_free)
       VG_(cli_free)( p );
 
-   // Remove HP_Chunk from malloclist, destroy
-   remove_HP_Chunk(hc, remove_handle);
+   // do a census!
+   hp_census();
 
-   hp_census();      // do a census!
-
-   VG_(free)( hc );
    VGP_POPCC(VgpCliMalloc);
 }
  
 
 void* SK_(malloc) ( Int n )
 {
-   return new_block( n, VG_(clo_alignment), /*is_zeroed*/False );
+   return new_block( NULL, n, VG_(clo_alignment), /*is_zeroed*/False );
 }
 
 void* SK_(__builtin_new) ( Int n )
 {
-   return new_block( n, VG_(clo_alignment), /*is_zeroed*/False );
+   return new_block( NULL, n, VG_(clo_alignment), /*is_zeroed*/False );
 }
 
 void* SK_(__builtin_vec_new) ( Int n )
 {
-   return new_block( n, VG_(clo_alignment), /*is_zeroed*/False );
+   return new_block( NULL, n, VG_(clo_alignment), /*is_zeroed*/False );
 }
 
 void* SK_(calloc) ( Int m, Int size )
 {
-   return new_block( m*size, VG_(clo_alignment), /*is_zeroed*/True );
+   return new_block( NULL, m*size, VG_(clo_alignment), /*is_zeroed*/True );
 }
 
 void *SK_(memalign)( Int align, Int n )
 {
-   return new_block( n, align, False );
+   return new_block( NULL, n, align, False );
 }
 
 void SK_(free) ( void* p )
@@ -1133,10 +1125,12 @@
 {
    switch (argv[0]) {
    case VG_USERREQ__MALLOCLIKE_BLOCK: {
+      void* res;
       void* p         = (void*)argv[1];
       UInt  sizeB     =        argv[2];
       *ret            = 0;
-      new_block_meta( p, sizeB, /*custom_malloc*/True );
+      res = new_block( p, sizeB, /*align -- ignored*/0, /*is_zeroed*/False );
+      sk_assert(res == p);
       return True;
    }
    case VG_USERREQ__FREELIKE_BLOCK: {