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. */
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 );
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
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;
}
/* ---------------------------------------------------------------------
}
+/* 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
{
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,
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. */
/* 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))
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. */
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;
/*------------------------------------------------------------*/
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 );
}
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 );
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;
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) );