Add definedness checking when dereferencing ptr during heuristic reachedness

Patch ensures that no heuristic reachedness is obtained with undefined data.



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13635 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/memcheck/mc_leakcheck.c b/memcheck/mc_leakcheck.c
index ffbf650..61a6814 100644
--- a/memcheck/mc_leakcheck.c
+++ b/memcheck/mc_leakcheck.c
@@ -685,19 +685,25 @@
       // Detects inner pointers to Std::String for layout being
       //     length capacity refcount char_array[] \0
       // where ptr points to the beginning of the char_array.
-      if ( ptr == ch->data + 3 * sizeof(SizeT)) {
-         const SizeT length = *((SizeT*)ch->data);
-         const SizeT capacity = *((SizeT*)ch->data+1);
-         if (length <= capacity
-             && (3 * sizeof(SizeT) + capacity + 1 == ch->szB)) {
-            // ??? could check there is no null byte from ptr to ptr+length-1
-            // ???    and that there is a null byte at ptr+length.
-            // ???
-            // ??? could check that ch->allockind is MC_AllocNew ???
-            // ??? probably not a good idea, as I guess stdstring
-            // ??? allocator can be done via custom allocator
-            // ??? or even a call to malloc ????
-            return LchStdString;
+      // Note: we check definedness for length and capacity but
+      // not for refcount, as refcount size might be smaller than
+      // a SizeT, giving a uninitialised hole in the first 3 SizeT.
+      if ( ptr == ch->data + 3 * sizeof(SizeT)
+           && MC_(is_valid_aligned_word)(ch->data + sizeof(SizeT))) {
+         const SizeT capacity = *((SizeT*)(ch->data + sizeof(SizeT)));
+         if (3 * sizeof(SizeT) + capacity + 1 == ch->szB
+            && MC_(is_valid_aligned_word)(ch->data)) {
+            const SizeT length = *((SizeT*)ch->data);
+            if (length <= capacity) {
+               // ??? could check there is no null byte from ptr to ptr+length-1
+               // ???    and that there is a null byte at ptr+length.
+               // ???
+               // ??? could check that ch->allockind is MC_AllocNew ???
+               // ??? probably not a good idea, as I guess stdstring
+               // ??? allocator can be done via custom allocator
+               // ??? or even a call to malloc ????
+               return LchStdString;
+            }
          }
       }
    }
@@ -718,7 +724,8 @@
       // 0-sized block. This trick does not work for 'new MyClass[0]'
       // because a chunk "word-sized" is allocated to store the (0) nr
       // of elements.
-      if ( ptr == ch->data + sizeof(SizeT)) {
+      if ( ptr == ch->data + sizeof(SizeT)
+           && MC_(is_valid_aligned_word)(ch->data)) {
          const SizeT nr_elts = *((SizeT*)ch->data);
          if (nr_elts > 0 && (ch->szB - sizeof(SizeT)) % nr_elts == 0) {
             // ??? could check that ch->allockind is MC_AllocNewVec ???
@@ -730,7 +737,8 @@
    if (HiS(LchMultipleInheritance, heur_set)) {
       // Detect inner pointer used for multiple inheritance.
       // Assumption is that the vtable pointers are before the object.
-      if (VG_IS_WORD_ALIGNED(ptr)) {
+      if (VG_IS_WORD_ALIGNED(ptr)
+          && MC_(is_valid_aligned_word)(ptr)) {
          Addr first_addr;
          Addr inner_addr;
 
@@ -744,7 +752,8 @@
          // in the last page.
          inner_addr = *((Addr*)ptr);
          if (VG_IS_WORD_ALIGNED(inner_addr) 
-             && inner_addr >= (Addr)VKI_PAGE_SIZE) {
+             && inner_addr >= (Addr)VKI_PAGE_SIZE
+             && MC_(is_valid_aligned_word)(ch->data)) {
             first_addr = *((Addr*)ch->data);
             if (VG_IS_WORD_ALIGNED(first_addr)
                 && first_addr >= (Addr)VKI_PAGE_SIZE
@@ -775,15 +784,10 @@
       return;
 
    if (ex->state == Reachable) {
-      // If block was considered reachable via an heuristic,
-      // and it is now directly reachable via ptr, clear the
-      // heuristic.
-      if (ex->heuristic && ptr == ch->data) {
-         // ch was up to now considered as reachable dur to
-         // ex->heuristic. We have a direct ptr now => clear
-         // the heuristic field.
+      if (ex->heuristic && ptr == ch->data)
+         // If block was considered reachable via an heuristic, and it is now
+         // directly reachable via ptr, clear the heuristic field.
          ex->heuristic = LchNone;
-      }
       return;
    }