]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
In vg_memory.c, startup_segment_callback, fix initialisation ordering
authorJulian Seward <jseward@acm.org>
Sat, 12 Jul 2003 12:11:39 +0000 (12:11 +0000)
committerJulian Seward <jseward@acm.org>
Sat, 12 Jul 2003 12:11:39 +0000 (12:11 +0000)
problem which caused the leak checker to misbehave following recent
PLT-bypass workaround.

In short, it is an error to announce to the skin, segments found which
belong to the low-level memory manager, because the skin may then mark
them as accessible to the client.  This is wrong, and the client
should only acquire accessible memory via malloc etc and stack
movement.  Now we carefully avoid mentioning any segment belonging to
the low level memory manager.

Take the opportunity to improve VG_(within_m_state_static) so that it
also detects pointers within the thread table.  This can reduce the
number of blocks the leak checker spuriously thinks are still
reachable.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@1751

addrcheck/ac_main.c
coregrind/vg_include.h
coregrind/vg_main.c
coregrind/vg_malloc2.c
coregrind/vg_memory.c
include/vg_skin.h
memcheck/mac_leakcheck.c
memcheck/mac_malloc_wrappers.c
memcheck/mac_shared.h
memcheck/mc_main.c

index c7e9dea14a759668af0dad11853781efc5fcb818..e4f2a6b3fe3c3b45d81dcd5dee76c5a4ff162716 100644 (file)
@@ -513,6 +513,25 @@ Bool ac_check_accessible ( Addr a, UInt len, Addr* bad_addr )
    return True;
 }
 
+/* The opposite; check that an address range is inaccessible. */
+static
+Bool ac_check_noaccess ( Addr a, UInt len, Addr* bad_addr )
+{
+   UInt  i;
+   UChar abit;
+   PROF_EVENT(48);
+   for (i = 0; i < len; i++) {
+      PROF_EVENT(49);
+      abit = get_abit(a);
+      if (abit == VGM_BIT_VALID) {
+         if (bad_addr != NULL) *bad_addr = a;
+         return False;
+      }
+      a++;
+   }
+   return True;
+}
+
 /* Check a zero-terminated ascii string.  Tricky -- don't want to
    examine the actual bytes, to find the end, until we're sure it is
    safe to do so. */
@@ -1234,6 +1253,7 @@ void SK_(pre_clo_init)(void)
    MAC_( ban_mem_heap)             = & ac_make_noaccess;
    MAC_(copy_mem_heap)             = & ac_copy_address_range_state;
    MAC_( die_mem_heap)             = & ac_make_noaccess;
+   MAC_(check_noaccess)            = & ac_check_noaccess;
 
    VG_(track_new_mem_startup)      ( & ac_new_mem_startup );
    VG_(track_new_mem_stack_signal) ( & ac_make_accessible );
index 0521471ca6df3845e3cd047b32fdfe15624dcb03..b7b229736efc6b98a54b653b1324263bcb34c588 100644 (file)
@@ -448,6 +448,10 @@ extern void  VG_(mallocSanityCheckAll)   ( void );
 extern void  VG_(show_all_arena_stats) ( void );
 extern Bool  VG_(is_empty_arena) ( ArenaId aid );
 
+/* Returns True if aa is inside any block mmap'd /dev/zero
+   by our low-level memory manager. */
+extern Bool  VG_(is_inside_segment_mmapd_by_low_level_MM)( Addr aa );
+
 
 /* ---------------------------------------------------------------------
    Exports of vg_intercept.c
index 7edbd9748aed49258028ffd02dc5586f84776b52..b89a411c56db73fe1f0208db97a5e3d3c07b5060 100644 (file)
@@ -1312,13 +1312,17 @@ Bool VG_(within_stack)(Addr a)
       return False;
 }
 
-Bool VG_(within_m_state_static)(Addr a)
+Bool VG_(within_m_state_static_OR_threads)(Addr a)
 {
    if (a >= ((Addr)(&VG_(m_state_static)))
-       && a <= ((Addr)(&VG_(m_state_static))) + sizeof(VG_(m_state_static)))
+       && a < ((Addr)(&VG_(m_state_static))) + sizeof(VG_(m_state_static)))
       return True;
-   else
-      return False;
+
+   if (a >= ((Addr)(&VG_(threads)[0]))
+       && a < ((Addr)(&VG_(threads)[VG_N_THREADS])))
+      return True;
+
+   return False;
 }
 
 /* ---------------------------------------------------------------------
index c41283b03e29a69ed0b02dcd87698d941e8ddb75..fe8fdebe74ea8a3700628bae41a6496e502c5738 100644 (file)
@@ -224,8 +224,30 @@ void ensure_mm_init ( void )
 }
 
 
+/* Returns True if aa is inside any segment mmap'd /dev/zero
+   by our low-level memory manager. */
+Bool VG_(is_inside_segment_mmapd_by_low_level_MM)( Addr aa )
+{
+   ArenaId ar;
+   Superblock* sb;
+
+   ensure_mm_init();
+
+   for (ar = 0; ar < VG_N_ARENAS; ar++) {
+      for (sb = vg_arena[ar].sblocks; sb; sb = sb->next) {
+        Addr sb_first_word = (Addr)sb;
+        Addr sb_last_word  
+            = (Addr)&(sb->payload_words[sb->n_payload_words-1]);
+        if (aa >= sb_first_word && aa <= sb_last_word)
+            return True;
+      }
+   }
+   return False;
+}
+
+
 /*------------------------------------------------------------*/
-/*--- Arena management stuff                               ---*/
+/*--- Superblock management stuff                          ---*/
 /*------------------------------------------------------------*/
 
 static
index 1241d9f727e8820b0a085ac99645c4d91a50b906..1fa456c51329da97b20244ebad30b35d0991a2fd 100644 (file)
@@ -153,8 +153,9 @@ void startup_segment_callback ( Addr start, UInt size,
 {
    UInt r_esp;
    Bool is_stack_segment;
+   Bool verbose = False; /* set to True for debugging */
 
-   if (0)
+   if (verbose)
       VG_(message)(Vg_DebugMsg,
                    "initial map %8x-%8x %c%c%c? %8x (%d) (%s)",
                    start,start+size,rr,ww,xx,foffset,
@@ -172,10 +173,26 @@ void startup_segment_callback ( Addr start, UInt size,
       return;
    }
 
+   /* If this segment corresponds to something mmap'd /dev/zero by the
+      low-level memory manager (vg_malloc2.c), skip it.  Clients
+      should never have access to the segments which hold valgrind
+      internal data.  And access to client data in the VG_AR_CLIENT
+      arena is mediated by the skin, so we don't want make it
+      accessible at this stage. */
+   if (VG_(is_inside_segment_mmapd_by_low_level_MM)( start )) {
+      if (verbose)
+         VG_(message)(Vg_DebugMsg,
+                      "   skipping %8x-%8x (owned by our MM)", 
+                      start, start+size );
+      /* Don't announce it to the skin. */
+      return;
+   }
+   
    /* This parallels what happens when we mmap some new memory */
    if (filename != NULL && xx == 'x') {
       VG_(new_exe_segment)( start, size );
    }
+
    VG_TRACK( new_mem_startup, start, size, rr=='r', ww=='w', xx=='x' );
 
    /* If this is the stack segment mark all below %esp as noaccess. */
index fa4022ca6c904397c662f6b09b037eb5f8fe51ef..5f7c63a0850f084defcc6c5cca7c1198c7a2d880 100644 (file)
@@ -256,11 +256,11 @@ extern ULong VG_(bbs_done);
 /* Get the simulated %esp */
 extern Addr VG_(get_stack_pointer) ( void );
 
-/* Detect if an address is within Valgrind's stack or Valgrind's
-   m_state_static;  useful for memory leak detectors to tell if a block
-   is used by Valgrind (and thus can be ignored). */
+/* Detect if an address is within Valgrind's stack, Valgrind's
+   m_state_static, or the VG_(threads) array.  This is useful for
+   memory leak detectors to rule out spurious pointers to a block. */
 extern Bool VG_(within_stack)(Addr a);
-extern Bool VG_(within_m_state_static)(Addr a);
+extern Bool VG_(within_m_state_static_OR_threads)(Addr a);
 
 /* Check if an address is 4-byte aligned */
 #define IS_ALIGNED4_ADDR(aaa_p) (0 == (((UInt)(aaa_p)) & 3))
index 42e9205fad7ac0b8c674e2589a638eb80530ecf4..9ad23601a6a8031555710154181cb905e6ea7633 100644 (file)
@@ -311,10 +311,10 @@ void vg_detect_memory_leaks_notify_addr ( Addr a, UInt word_at_a )
       where the .bss segment has been put.  If you can, drop me a
       line.  
    */
-   if (VG_(within_stack)(a))              return;
-   if (VG_(within_m_state_static)(a))     return;
-   if (a == (Addr)(&lc_min_mallocd_addr)) return;
-   if (a == (Addr)(&lc_max_mallocd_addr)) return;
+   if (VG_(within_stack)(a))                      return;
+   if (VG_(within_m_state_static_OR_threads)(a))  return;
+   if (a == (Addr)(&lc_min_mallocd_addr))         return;
+   if (a == (Addr)(&lc_max_mallocd_addr))         return;
 
    /* OK, let's get on and do something Useful for a change. */
 
index 42434de82026ebb72d4dabe4383618212a245b44..71757d9cc556060c4ad9e6ca9dfaba8dbebfc955 100644 (file)
@@ -45,10 +45,13 @@ static UInt cmalloc_bs_mallocd = 0;
 UInt VG_(vg_malloc_redzone_szB) = 16;
 
 /* Function pointers for the two skins to track interesting events. */
-void (*MAC_(new_mem_heap)) ( Addr a, UInt len, Bool is_inited );
-void (*MAC_(ban_mem_heap)) ( Addr a, UInt len );
-void (*MAC_(die_mem_heap)) ( Addr a, UInt len );
-void (*MAC_(copy_mem_heap))( Addr from, Addr to, UInt len );
+void (*MAC_(new_mem_heap)) ( Addr a, UInt len, Bool is_inited )  = NULL;
+void (*MAC_(ban_mem_heap)) ( Addr a, UInt len )                  = NULL;
+void (*MAC_(die_mem_heap)) ( Addr a, UInt len )                  = NULL;
+void (*MAC_(copy_mem_heap))( Addr from, Addr to, UInt len )      = NULL;
+
+/* Function pointers for internal sanity checking. */
+Bool (*MAC_(check_noaccess))( Addr a, UInt len, Addr* bad_addr ) = NULL;
 
 
 /*------------------------------------------------------------*/
@@ -134,13 +137,14 @@ void add_MAC_Chunk ( ThreadState* tst, Addr p, UInt size, MAC_AllocKind kind )
    mc->allockind = kind;
    mc->where     = VG_(get_ExeContext)(tst);
 
-   /* The following line puts the shadow chunk, and hence the pointer
-      to the real chunk, off-limits to the client.  This seems to be
-      necessary to make the leak checker work reliably.  Problem is,
-      this seems to point to something deeper being wrong: this chunk
-      is allocated in the AR_SKIN arena and so should by default be
-      off-limits to the client anyway. */
-   MAC_(ban_mem_heap)( (Addr)mc, sizeof(MAC_Chunk));
+   /* Paranoia ... ensure this area is off-limits to the client, so
+      the mc->data field isn't visible to the leak checker.  If memory
+      management is working correctly, anything pointer returned by
+      VG_(malloc) should be noaccess as far as the client is
+      concerned. */
+   if (!MAC_(check_noaccess)( (Addr)mc, sizeof(MAC_Chunk), NULL )) {
+      VG_(skin_panic)("add_MAC_chunk: shadow area is accessible");
+   } 
 
    VG_(HT_add_node)( MAC_(malloc_list), (VgHashNode*)mc );
 }
index 93bedab6d7751f4a4143d55a0175d758e7e1ea2f..5cb989316c8288c895ad361e09a40c6de3da4dfb 100644 (file)
@@ -267,6 +267,9 @@ extern void (*MAC_(ban_mem_heap)) ( Addr a, UInt len );
 extern void (*MAC_(die_mem_heap)) ( Addr a, UInt len );
 extern void (*MAC_(copy_mem_heap))( Addr from, Addr to, UInt len );
 
+/* Function pointers for internal sanity checking. */
+extern Bool (*MAC_(check_noaccess))( Addr a, UInt len, Addr* bad_addr );
+
 /* Used in describe_addr() */
 extern Bool (*MAC_(describe_addr_supp))    ( Addr a, AddrInfo* ai );
 
index 167a2ba82b60882fb03bf9be16390b274dceb8f0..28a971248cd66f9d116322a3fa010e2da31db736 100644 (file)
@@ -518,6 +518,27 @@ static void mc_copy_address_range_state ( Addr src, Addr dst, UInt len )
    exist, *bad_addr is set to the offending address, so the caller can
    know what it is. */
 
+/* Returns True if [a .. a+len) is not addressible.  Otherwise,
+   returns False, and if bad_addr is non-NULL, sets *bad_addr to
+   indicate the lowest failing address.  Functions below are
+   similar. */
+Bool MC_(check_noaccess) ( Addr a, UInt len, Addr* bad_addr )
+{
+   UInt  i;
+   UChar abit;
+   PROF_EVENT(42);
+   for (i = 0; i < len; i++) {
+      PROF_EVENT(43);
+      abit = get_abit(a);
+      if (abit == VGM_BIT_VALID) {
+         if (bad_addr != NULL) *bad_addr = a;
+         return False;
+      }
+      a++;
+   }
+   return True;
+}
+
 Bool MC_(check_writable) ( Addr a, UInt len, Addr* bad_addr )
 {
    UInt  i;
@@ -1655,6 +1676,7 @@ void SK_(pre_clo_init)(void)
    MAC_( ban_mem_heap)             = & MC_(make_noaccess);
    MAC_(copy_mem_heap)             = & mc_copy_address_range_state;
    MAC_( die_mem_heap)             = & MC_(make_noaccess);
+   MAC_(check_noaccess)            = & MC_(check_noaccess);
 
    VG_(track_new_mem_startup)      ( & mc_new_mem_startup );
    VG_(track_new_mem_stack_signal) ( & MC_(make_writable) );