Commit cfbd22d7 by Frank Ch. Eigler Committed by Frank Ch. Eigler

Adopt splay trees for object database.

2004-06-24  Frank Ch. Eigler  <fche@redhat.com>

	Adopt splay trees for object database.
	* Makefile.am: Copy splay-tree.* from libiberty.
	* Makefile.in, testsuite/Makefile.in: Regenerated.
	* mf-runtime.h.in (__mf_unregister): Add third parameter (type).
	* mf-hooks[123].c (*): Add new third parameter to mf_unregister.
	* mf-impl.h (BEGIN_PROTECT): Remove some trace text.
	* mf-runtime.c: Rewrite code dealing with object database to use
	libiberty splay trees.  Remove tree liveness aging option.
	* testsuite/libmudflap.c/fail18-frag.c: Add volatile flag.

From-SVN: r83611
parent 79066482
2004-06-24 Frank Ch. Eigler <fche@redhat.com>
Adopt splay trees for object database.
* Makefile.am: Copy splay-tree.* from libiberty.
* Makefile.in, testsuite/Makefile.in: Regenerated.
* mf-runtime.h.in (__mf_unregister): Add third parameter (type).
* mf-hooks[123].c (*): Add new third parameter to mf_unregister.
* mf-impl.h (BEGIN_PROTECT): Remove some trace text.
* mf-runtime.c: Rewrite code dealing with object database to use
libiberty splay trees. Remove tree liveness aging option.
* testsuite/libmudflap.c/fail18-frag.c: Add volatile flag.
2004-06-15 Paolo Bonzini <bonzini@gnu.org> 2004-06-15 Paolo Bonzini <bonzini@gnu.org>
* configure.ac: New name of configure.in. Update * configure.ac: New name of configure.in. Update
......
...@@ -20,18 +20,29 @@ endif ...@@ -20,18 +20,29 @@ endif
toolexeclib_LTLIBRARIES = libmudflap.la $(libmudflapth) toolexeclib_LTLIBRARIES = libmudflap.la $(libmudflapth)
include_HEADERS = mf-runtime.h include_HEADERS = mf-runtime.h
# Copy this out of libiberty's source tree, so it can be built here via libtool
splay-tree.c:
rm -f $@
$(LN_S) $(srcdir)/../libiberty/splay-tree.c $@
# Copy this so that top-level include/ does not have to be put into -I path
splay-tree.h:
rm -f $@
$(LN_S) $(srcdir)/../include/splay-tree.h $@
libmudflap_la_SOURCES = \ libmudflap_la_SOURCES = \
mf-runtime.c \ mf-runtime.c \
mf-heuristics.c \ mf-heuristics.c \
mf-hooks1.c \ mf-hooks1.c \
mf-hooks2.c mf-hooks2.c
mf-runtime.lo: mf-runtime.c splay-tree.c splay-tree.h
libmudflap_la_LIBADD = libmudflap_la_LIBADD =
libmudflap_la_DEPENDENCIES = $(libmudflap_la_LIBADD) libmudflap_la_DEPENDENCIES = $(libmudflap_la_LIBADD)
clean-local: clean-local:
rm -f pth/*.o pth/*.lo rm -f pth/*.o pth/*.lo
rm -f splay-tree.c splay-tree.h
pth/mf-runtime.lo: mf-runtime.c mf-runtime.h mf-impl.h pth/mf-runtime.lo: mf-runtime.c mf-runtime.h mf-impl.h splay-tree.c splay-tree.h
$(LTCOMPILE) -DLIBMUDFLAPTH -c $(srcdir)/mf-runtime.c -o $@ $(LTCOMPILE) -DLIBMUDFLAPTH -c $(srcdir)/mf-runtime.c -o $@
pth/mf-heuristics.lo: mf-heuristics.c mf-runtime.h mf-impl.h pth/mf-heuristics.lo: mf-heuristics.c mf-runtime.h mf-impl.h
$(LTCOMPILE) -DLIBMUDFLAPTH -c $(srcdir)/mf-heuristics.c -o $@ $(LTCOMPILE) -DLIBMUDFLAPTH -c $(srcdir)/mf-heuristics.c -o $@
......
...@@ -50,7 +50,7 @@ DIST_COMMON = $(am__configure_deps) $(include_HEADERS) \ ...@@ -50,7 +50,7 @@ DIST_COMMON = $(am__configure_deps) $(include_HEADERS) \
subdir = . subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
$(top_srcdir)/configure.in $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4) $(ACLOCAL_M4)
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
...@@ -818,10 +818,21 @@ uninstall-info: uninstall-info-recursive ...@@ -818,10 +818,21 @@ uninstall-info: uninstall-info-recursive
uninstall-info-am uninstall-toolexeclibLTLIBRARIES uninstall-info-am uninstall-toolexeclibLTLIBRARIES
# Copy this out of libiberty's source tree, so it can be built here via libtool
splay-tree.c:
rm -f $@
$(LN_S) $(srcdir)/../libiberty/splay-tree.c $@
# Copy this so that top-level include/ does not have to be put into -I path
splay-tree.h:
rm -f $@
$(LN_S) $(srcdir)/../include/splay-tree.h $@
mf-runtime.lo: mf-runtime.c splay-tree.c splay-tree.h
clean-local: clean-local:
rm -f pth/*.o pth/*.lo rm -f pth/*.o pth/*.lo
rm -f splay-tree.c splay-tree.h
pth/mf-runtime.lo: mf-runtime.c mf-runtime.h mf-impl.h pth/mf-runtime.lo: mf-runtime.c mf-runtime.h mf-impl.h splay-tree.c splay-tree.h
$(LTCOMPILE) -DLIBMUDFLAPTH -c $(srcdir)/mf-runtime.c -o $@ $(LTCOMPILE) -DLIBMUDFLAPTH -c $(srcdir)/mf-runtime.c -o $@
pth/mf-heuristics.lo: mf-heuristics.c mf-runtime.h mf-impl.h pth/mf-heuristics.lo: mf-heuristics.c mf-runtime.h mf-impl.h
$(LTCOMPILE) -DLIBMUDFLAPTH -c $(srcdir)/mf-heuristics.c -o $@ $(LTCOMPILE) -DLIBMUDFLAPTH -c $(srcdir)/mf-heuristics.c -o $@
......
...@@ -199,7 +199,8 @@ WRAPPER(void *, realloc, void *buf, size_t c) ...@@ -199,7 +199,8 @@ WRAPPER(void *, realloc, void *buf, size_t c)
__mf_opts.wipe_heap = 0; __mf_opts.wipe_heap = 0;
if (LIKELY(buf)) if (LIKELY(buf))
__mfu_unregister (buf, 0); __mfu_unregister (buf, 0, __MF_TYPE_HEAP_I);
/* NB: underlying region may have been __MF_TYPE_HEAP. */
if (LIKELY(result)) if (LIKELY(result))
{ {
...@@ -250,7 +251,8 @@ WRAPPER(void, free, void *buf) ...@@ -250,7 +251,8 @@ WRAPPER(void, free, void *buf)
} }
UNLOCKTH (); UNLOCKTH ();
__mf_unregister (buf, 0); __mf_unregister (buf, 0, __MF_TYPE_HEAP_I);
/* NB: underlying region may have been __MF_TYPE_HEAP. */
if (UNLIKELY(__mf_opts.free_queue_length > 0)) if (UNLIKELY(__mf_opts.free_queue_length > 0))
{ {
...@@ -378,7 +380,7 @@ WRAPPER(int , munmap, void *start, size_t length) ...@@ -378,7 +380,7 @@ WRAPPER(int , munmap, void *start, size_t length)
uintptr_t offset; uintptr_t offset;
for (offset=0; offset<length; offset+=ps) for (offset=0; offset<length; offset+=ps)
__mf_unregister ((void *) CLAMPADD (base, offset), ps); __mf_unregister ((void *) CLAMPADD (base, offset), ps, __MF_TYPE_HEAP_I);
} }
return result; return result;
} }
...@@ -419,7 +421,7 @@ __mf_wrap_alloca_indirect (size_t c) ...@@ -419,7 +421,7 @@ __mf_wrap_alloca_indirect (size_t c)
((uintptr_t) alloca_history->stack DEEPER_THAN (uintptr_t) stack)) ((uintptr_t) alloca_history->stack DEEPER_THAN (uintptr_t) stack))
{ {
struct alloca_tracking *next = alloca_history->next; struct alloca_tracking *next = alloca_history->next;
__mf_unregister (alloca_history->ptr, 0); __mf_unregister (alloca_history->ptr, 0, __MF_TYPE_HEAP);
CALL_REAL (free, alloca_history->ptr); CALL_REAL (free, alloca_history->ptr);
CALL_REAL (free, alloca_history); CALL_REAL (free, alloca_history);
alloca_history = next; alloca_history = next;
......
...@@ -624,7 +624,7 @@ WRAPPER2(int, fclose, FILE *stream) ...@@ -624,7 +624,7 @@ WRAPPER2(int, fclose, FILE *stream)
"fclose stream"); "fclose stream");
resp = fclose (stream); resp = fclose (stream);
#ifdef MF_REGISTER_fopen #ifdef MF_REGISTER_fopen
__mf_unregister (stream, sizeof (*stream)); __mf_unregister (stream, sizeof (*stream), MF_REGISTER_fopen);
#endif #endif
return resp; return resp;
...@@ -1101,7 +1101,7 @@ WRAPPER2(int, closedir, DIR *dir) ...@@ -1101,7 +1101,7 @@ WRAPPER2(int, closedir, DIR *dir)
TRACE ("%s\n", __PRETTY_FUNCTION__); TRACE ("%s\n", __PRETTY_FUNCTION__);
MF_VALIDATE_EXTENT (dir, 0, __MF_CHECK_WRITE, "closedir dir"); MF_VALIDATE_EXTENT (dir, 0, __MF_CHECK_WRITE, "closedir dir");
#ifdef MF_REGISTER_opendir #ifdef MF_REGISTER_opendir
__mf_unregister (dir, MF_RESULT_SIZE_opendir); __mf_unregister (dir, MF_RESULT_SIZE_opendir, MF_REGISTER_opendir);
#endif #endif
return closedir (dir); return closedir (dir);
} }
...@@ -1381,7 +1381,7 @@ WRAPPER2(int, pclose, FILE *stream) ...@@ -1381,7 +1381,7 @@ WRAPPER2(int, pclose, FILE *stream)
"pclose stream"); "pclose stream");
resp = pclose (stream); resp = pclose (stream);
#ifdef MF_REGISTER_fopen #ifdef MF_REGISTER_fopen
__mf_unregister (stream, sizeof (*stream)); __mf_unregister (stream, sizeof (*stream), MF_REGISTER_fopen);
#endif #endif
return resp; return resp;
} }
...@@ -1499,7 +1499,7 @@ WRAPPER2(int, dlclose, void *handle) ...@@ -1499,7 +1499,7 @@ WRAPPER2(int, dlclose, void *handle)
MF_VALIDATE_EXTENT (handle, 0, __MF_CHECK_READ, "dlclose handle"); MF_VALIDATE_EXTENT (handle, 0, __MF_CHECK_READ, "dlclose handle");
resp = dlclose (handle); resp = dlclose (handle);
#ifdef MF_REGISTER_dlopen #ifdef MF_REGISTER_dlopen
__mf_unregister (handle, 0); __mf_unregister (handle, 0, MF_REGISTER_dlopen);
#endif #endif
return resp; return resp;
} }
...@@ -1637,7 +1637,7 @@ WRAPPER2(int, shmdt, const void *shmaddr) ...@@ -1637,7 +1637,7 @@ WRAPPER2(int, shmdt, const void *shmaddr)
TRACE ("%s\n", __PRETTY_FUNCTION__); TRACE ("%s\n", __PRETTY_FUNCTION__);
resp = shmdt (shmaddr); resp = shmdt (shmaddr);
#ifdef MF_REGISTER_shmat #ifdef MF_REGISTER_shmat
__mf_unregister ((void *)shmaddr, 0); __mf_unregister ((void *)shmaddr, 0, MF_REGISTER_shmat);
#endif #endif
return resp; return resp;
} }
......
...@@ -273,7 +273,7 @@ __mf_pthread_cleanup (void *arg) ...@@ -273,7 +273,7 @@ __mf_pthread_cleanup (void *arg)
/* XXX: This unregistration is not safe on platforms where distinct /* XXX: This unregistration is not safe on platforms where distinct
threads share errno (or at least its virtual address). */ threads share errno (or at least its virtual address). */
if (pi->thread_errno != NULL) if (pi->thread_errno != NULL)
__mf_unregister (pi->thread_errno, sizeof (int)); __mf_unregister (pi->thread_errno, sizeof (int), __MF_TYPE_GUESS);
/* XXX: Only detached threads should designate themselves as dead /* XXX: Only detached threads should designate themselves as dead
here. Non-detached threads are marked dead after their here. Non-detached threads are marked dead after their
......
...@@ -365,10 +365,6 @@ ret __mfwrap_ ## fname (__VA_ARGS__) ...@@ -365,10 +365,6 @@ ret __mfwrap_ ## fname (__VA_ARGS__)
else if (UNLIKELY (__mf_state == reentrant)) \ else if (UNLIKELY (__mf_state == reentrant)) \
{ \ { \
extern unsigned long __mf_reentrancy; \ extern unsigned long __mf_reentrancy; \
if (UNLIKELY (__mf_opts.verbose_trace)) { \
write (2, "mf: reentrancy detected in `", 28); \
write (2, __PRETTY_FUNCTION__, strlen(__PRETTY_FUNCTION__)); \
write (2, "'\n", 2); } \
__mf_reentrancy ++; \ __mf_reentrancy ++; \
return CALL_REAL(fname, __VA_ARGS__); \ return CALL_REAL(fname, __VA_ARGS__); \
} \ } \
...@@ -381,7 +377,7 @@ ret __mfwrap_ ## fname (__VA_ARGS__) ...@@ -381,7 +377,7 @@ ret __mfwrap_ ## fname (__VA_ARGS__)
/* Unlocked variants of main entry points from mf-runtime.h. */ /* Unlocked variants of main entry points from mf-runtime.h. */
extern void __mfu_check (void *ptr, size_t sz, int type, const char *location); extern void __mfu_check (void *ptr, size_t sz, int type, const char *location);
extern void __mfu_register (void *ptr, size_t sz, int type, const char *name); extern void __mfu_register (void *ptr, size_t sz, int type, const char *name);
extern void __mfu_unregister (void *ptr, size_t sz); extern void __mfu_unregister (void *ptr, size_t sz, int type);
extern void __mfu_report (); extern void __mfu_report ();
extern int __mfu_set_options (const char *opts); extern int __mfu_set_options (const char *opts);
......
...@@ -67,6 +67,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA ...@@ -67,6 +67,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "mf-runtime.h" #include "mf-runtime.h"
#include "mf-impl.h" #include "mf-impl.h"
#include "splay-tree.h"
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
...@@ -145,7 +146,6 @@ const void *threads_active_p = (void *) pthread_join; ...@@ -145,7 +146,6 @@ const void *threads_active_p = (void *) pthread_join;
static unsigned long __mf_count_check; static unsigned long __mf_count_check;
static unsigned long __mf_lookup_cache_reusecount [LOOKUP_CACHE_SIZE_MAX]; static unsigned long __mf_lookup_cache_reusecount [LOOKUP_CACHE_SIZE_MAX];
static unsigned long __mf_treerot_left, __mf_treerot_right;
static unsigned long __mf_count_register; static unsigned long __mf_count_register;
static unsigned long __mf_total_register_size [__MF_TYPE_MAX+1]; static unsigned long __mf_total_register_size [__MF_TYPE_MAX+1];
static unsigned long __mf_count_unregister; static unsigned long __mf_count_unregister;
...@@ -191,20 +191,12 @@ typedef struct __mf_object ...@@ -191,20 +191,12 @@ typedef struct __mf_object
#endif #endif
} __mf_object_t; } __mf_object_t;
/* Live objects: splay trees, separated by type, ordered on .low (base address). */
typedef struct __mf_object_tree /* Actually stored as static vars within lookup function below. */
{
__mf_object_t data;
struct __mf_object_tree *left;
struct __mf_object_tree *right;
} __mf_object_tree_t;
/* Live objects: binary tree on __mf_object_t.low */
static __mf_object_tree_t *__mf_object_root;
/* Dead objects: circular arrays; _MIN_CEM .. _MAX_CEM only */ /* Dead objects: circular arrays; _MIN_CEM .. _MAX_CEM only */
static unsigned __mf_object_dead_head[__MF_TYPE_MAX_CEM+1]; /* next empty spot */ static unsigned __mf_object_dead_head[__MF_TYPE_MAX_CEM+1]; /* next empty spot */
static __mf_object_tree_t *__mf_object_cemetary[__MF_TYPE_MAX_CEM+1][__MF_PERSIST_MAX]; static __mf_object_t *__mf_object_cemetary[__MF_TYPE_MAX_CEM+1][__MF_PERSIST_MAX];
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
...@@ -213,16 +205,17 @@ static __mf_object_tree_t *__mf_object_cemetary[__MF_TYPE_MAX_CEM+1][__MF_PERSIS ...@@ -213,16 +205,17 @@ static __mf_object_tree_t *__mf_object_cemetary[__MF_TYPE_MAX_CEM+1][__MF_PERSIS
static void __mf_init () CTOR; static void __mf_init () CTOR;
static void __mf_sigusr1_respond (); static void __mf_sigusr1_respond ();
static unsigned __mf_find_objects (uintptr_t ptr_low, uintptr_t ptr_high, static unsigned __mf_find_objects (uintptr_t ptr_low, uintptr_t ptr_high,
__mf_object_tree_t **objs, unsigned max_objs); __mf_object_t **objs, unsigned max_objs);
static unsigned __mf_find_objects2 (uintptr_t ptr_low, uintptr_t ptr_high,
__mf_object_t **objs, unsigned max_objs, int type);
static unsigned __mf_find_dead_objects (uintptr_t ptr_low, uintptr_t ptr_high, static unsigned __mf_find_dead_objects (uintptr_t ptr_low, uintptr_t ptr_high,
__mf_object_tree_t **objs, unsigned max_objs); __mf_object_t **objs, unsigned max_objs);
static void __mf_link_object (__mf_object_tree_t *obj);
static void __mf_age_tree (__mf_object_tree_t *obj);
static void __mf_adapt_cache (); static void __mf_adapt_cache ();
static void __mf_unlink_object (__mf_object_tree_t *obj);
static void __mf_describe_object (__mf_object_t *obj); static void __mf_describe_object (__mf_object_t *obj);
static unsigned __mf_watch_or_not (void *ptr, size_t sz, char flag); static unsigned __mf_watch_or_not (void *ptr, size_t sz, char flag);
static splay_tree __mf_object_tree (int type);
static void __mf_link_object (__mf_object_t *node);
static void __mf_unlink_object (__mf_object_t *node);
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
...@@ -233,7 +226,6 @@ __mf_set_default_options () ...@@ -233,7 +226,6 @@ __mf_set_default_options ()
{ {
memset (& __mf_opts, 0, sizeof (__mf_opts)); memset (& __mf_opts, 0, sizeof (__mf_opts));
__mf_opts.tree_aging = 13037;
__mf_opts.adapt_cache = 1000003; __mf_opts.adapt_cache = 1000003;
__mf_opts.abbreviate = 1; __mf_opts.abbreviate = 1;
__mf_opts.verbose_violations = 1; __mf_opts.verbose_violations = 1;
...@@ -305,9 +297,6 @@ options [] = ...@@ -305,9 +297,6 @@ options [] =
{"internal-checking", {"internal-checking",
"perform more expensive internal checking", "perform more expensive internal checking",
set_option, 1, &__mf_opts.internal_checking}, set_option, 1, &__mf_opts.internal_checking},
{"age-tree",
"age the object tree after N accesses for working set",
read_integer_option, 1000000, &__mf_opts.tree_aging},
{"print-leaks", {"print-leaks",
"print any memory leaks at program shutdown", "print any memory leaks at program shutdown",
set_option, 1, &__mf_opts.print_leaks}, set_option, 1, &__mf_opts.print_leaks},
...@@ -610,8 +599,20 @@ struct __mf_dynamic_entry __mf_dynamic [] = ...@@ -610,8 +599,20 @@ struct __mf_dynamic_entry __mf_dynamic [] =
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
/* Lookup & manage automatic initialization of the five or so splay trees. */
static splay_tree
__mf_object_tree (int type)
{
static splay_tree trees [__MF_TYPE_MAX+1];
assert (type >= 0 && type <= __MF_TYPE_MAX);
if (UNLIKELY (trees[type] == NULL))
trees[type] = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
return trees[type];
}
void __mf_init () void
__mf_init ()
{ {
char *ov = 0; char *ov = 0;
...@@ -759,53 +760,72 @@ void __mfu_check (void *ptr, size_t sz, int type, const char *location) ...@@ -759,53 +760,72 @@ void __mfu_check (void *ptr, size_t sz, int type, const char *location)
unsigned heuristics = 0; unsigned heuristics = 0;
/* Advance aging/adaptation counters. */ /* Advance aging/adaptation counters. */
if (__mf_object_root)
{
static unsigned aging_count;
static unsigned adapt_count; static unsigned adapt_count;
aging_count ++;
adapt_count ++; adapt_count ++;
if (UNLIKELY (__mf_opts.tree_aging > 0 &&
aging_count > __mf_opts.tree_aging))
{
aging_count = 0;
__mf_age_tree (__mf_object_root);
}
if (UNLIKELY (__mf_opts.adapt_cache > 0 && if (UNLIKELY (__mf_opts.adapt_cache > 0 &&
adapt_count > __mf_opts.adapt_cache)) adapt_count > __mf_opts.adapt_cache))
{ {
adapt_count = 0; adapt_count = 0;
__mf_adapt_cache (); __mf_adapt_cache ();
} }
}
/* Looping only occurs if heuristics were triggered. */ /* Looping only occurs if heuristics were triggered. */
while (judgement == 0) while (judgement == 0)
{ {
__mf_object_tree_t* ovr_obj[1]; DECLARE (void, free, void *p);
__mf_object_t* ovr_obj[1];
unsigned obj_count; unsigned obj_count;
__mf_object_t** all_ovr_obj = NULL;
__mf_object_t** dealloc_me = NULL;
unsigned i;
/* Find all overlapping objects. Be optimistic that there is just one. */
obj_count = __mf_find_objects (ptr_low, ptr_high, ovr_obj, 1); obj_count = __mf_find_objects (ptr_low, ptr_high, ovr_obj, 1);
if (UNLIKELY (obj_count > 1))
{
/* Allocate a real buffer and do the search again. */
DECLARE (void *, malloc, size_t c);
unsigned n;
all_ovr_obj = CALL_REAL (malloc, (sizeof (__mf_object_t *) *
obj_count));
if (all_ovr_obj == NULL) abort ();
n = __mf_find_objects (ptr_low, ptr_high, all_ovr_obj, obj_count);
assert (n == obj_count);
dealloc_me = all_ovr_obj;
}
else
{
all_ovr_obj = ovr_obj;
dealloc_me = NULL;
}
if (LIKELY (obj_count == 1)) /* A single hit! */ /* Update object statistics. */
for (i = 0; i < obj_count; i++)
{ {
__mf_object_t *obj = & ovr_obj[0]->data; __mf_object_t *obj = all_ovr_obj[i];
assert (obj != NULL); assert (obj != NULL);
if (LIKELY (ptr_low >= obj->low && ptr_high <= obj->high))
{
/* XXX: hope for no overflow! */
if (type == __MF_CHECK_READ) if (type == __MF_CHECK_READ)
obj->read_count ++; obj->read_count ++;
else else
obj->write_count ++; obj->write_count ++;
obj->liveness ++; obj->liveness ++;
}
/* Iterate over the various objects. There are a number of special cases. */
for (i = 0; i < obj_count; i++)
{
__mf_object_t *obj = all_ovr_obj[i];
/* Any __MF_TYPE_NOACCESS hit is bad. */
if (UNLIKELY (obj->type == __MF_TYPE_NOACCESS)) if (UNLIKELY (obj->type == __MF_TYPE_NOACCESS))
judgement = -1; judgement = -1;
else if (UNLIKELY (obj->watching_p))
/* Any object with a watch flag is bad. */
if (UNLIKELY (obj->watching_p))
judgement = -2; /* trigger VIOL_WATCH */ judgement = -2; /* trigger VIOL_WATCH */
else if (UNLIKELY (__mf_opts.check_initialization
/* A read from an uninitialized object is bad. */
if (UNLIKELY (__mf_opts.check_initialization
/* reading */ /* reading */
&& type == __MF_CHECK_READ && type == __MF_CHECK_READ
/* not written */ /* not written */
...@@ -813,127 +833,33 @@ void __mfu_check (void *ptr, size_t sz, int type, const char *location) ...@@ -813,127 +833,33 @@ void __mfu_check (void *ptr, size_t sz, int type, const char *location)
/* uninitialized (heap) */ /* uninitialized (heap) */
&& obj->type == __MF_TYPE_HEAP)) && obj->type == __MF_TYPE_HEAP))
judgement = -1; judgement = -1;
else
{
/* Valid access. */
entry->low = obj->low;
entry->high = obj->high;
judgement = 1;
}
} }
/* The object did not cover the entire accessed region. */
}
else if (LIKELY (obj_count > 1))
{
__mf_object_tree_t **all_ovr_objs;
unsigned n;
DECLARE (void *, malloc, size_t c);
DECLARE (void, free, void *p);
all_ovr_objs = CALL_REAL (malloc, (sizeof (__mf_object_tree_t *) *
obj_count));
if (all_ovr_objs == NULL) abort ();
n = __mf_find_objects (ptr_low, ptr_high, all_ovr_objs, obj_count);
assert (n == obj_count);
/* Confirm that accessed range is covered by first/last object. */ /* We now know that the access spans one or more valid objects. */
if (LIKELY ((ptr_low >= all_ovr_objs[0]->data.low) && if (LIKELY (judgement >= 0))
(ptr_high <= all_ovr_objs[obj_count-1]->data.high))) for (i = 0; i < obj_count; i++)
{ {
/* Presume valid access. */ __mf_object_t *obj = all_ovr_obj[i];
judgement = 1;
/* Confirm that intermediate objects are /* Is this access entirely contained within this object? */
contiguous and share a single name. Thus they if (LIKELY (ptr_low >= obj->low && ptr_high <= obj->high))
are likely split up GUESS regions, or mmap
pages. The idea of the name check is to
prevent an oversize access to a
stack-registered object (followed by some GUESS
type) from being accepted as a hit. */
for (n=0; n<obj_count-1; n++)
{
__mf_object_t *obj = & (all_ovr_objs[n]->data);
__mf_object_t *nextobj = & (all_ovr_objs[n+1]->data);
if (UNLIKELY (obj->type == __MF_TYPE_NOACCESS))
judgement = -1; /* Force error. */
if (UNLIKELY (judgement == 1 &&
(obj->high + 1 != nextobj->low)))
judgement = 0; /* Cancel presumption. */
if (UNLIKELY (judgement == 1 &&
(obj->name != nextobj->name)))
judgement = 0; /* Cancel presumption. */
/* NB: strcmp above is not necessary since the
same literal string pointer is normally
used when creating regions. */
/* XXX: hope for no overflow! */
if (type == __MF_CHECK_READ)
obj->read_count ++;
else
obj->write_count ++;
obj->liveness ++;
}
/* If the access is otherwise successful, check whether
any of the covered objects are being watched. */
if (judgement > 0)
{
unsigned i;
for (i=0; i<obj_count; i++)
if (all_ovr_objs[i]->data.watching_p)
judgement = -2; /* trigger VIOL_WATCH */
}
/* Check for uninitialized reads. */
if (judgement > 0 &&
__mf_opts.check_initialization &&
type == __MF_CHECK_READ)
{
unsigned i;
unsigned written_count = 0;
for (i=0; i<obj_count; i++)
{ {
__mf_object_t *obj = & all_ovr_objs[i]->data; /* Valid access. */
entry->low = obj->low;
if (obj->write_count entry->high = obj->high;
|| obj->type == __MF_TYPE_HEAP_I judgement = 1;
|| obj->type == __MF_TYPE_GUESS)
written_count ++;
} }
/* Check for ALL pieces having been written-to. /* XXX: Access runs off left or right side of this
XXX: should this be ANY instead? */ object. That could be okay, if there are
if (written_count != obj_count) other objects that fill in all the holes. */
judgement = -1;
} }
/* Fill out the cache with the bounds of the first if (dealloc_me != NULL)
object and the last object that covers this CALL_REAL (free, dealloc_me);
cache line (== includes the same __MF_CACHE_INDEX).
This could let this cache line span *two* distinct
registered objects: a peculiar but reasonable
situation. The cache line may not include the
entire object though. */
if (judgement > 0)
{
unsigned i;
entry->low = all_ovr_objs[0]->data.low;
for (i=0; i<obj_count; i++)
{
uintptr_t high = all_ovr_objs[i]->data.high;
if (__MF_CACHE_INDEX (high) == entry_idx)
entry->high = high;
}
}
}
CALL_REAL (free, all_ovr_objs);
}
/* If the judgment is still unknown at this stage, loop
around at most one more time. */
if (judgement == 0) if (judgement == 0)
{ {
if (heuristics++ < 2) /* XXX parametrize this number? */ if (heuristics++ < 2) /* XXX parametrize this number? */
...@@ -969,29 +895,29 @@ void __mfu_check (void *ptr, size_t sz, int type, const char *location) ...@@ -969,29 +895,29 @@ void __mfu_check (void *ptr, size_t sz, int type, const char *location)
} }
static __mf_object_tree_t * static __mf_object_t *
__mf_insert_new_object (uintptr_t low, uintptr_t high, int type, __mf_insert_new_object (uintptr_t low, uintptr_t high, int type,
const char *name, uintptr_t pc) const char *name, uintptr_t pc)
{ {
DECLARE (void *, calloc, size_t c, size_t n); DECLARE (void *, calloc, size_t c, size_t n);
__mf_object_tree_t *new_obj; __mf_object_t *new_obj;
new_obj = CALL_REAL (calloc, 1, sizeof(__mf_object_tree_t)); new_obj = CALL_REAL (calloc, 1, sizeof(__mf_object_t));
new_obj->data.low = low; new_obj->low = low;
new_obj->data.high = high; new_obj->high = high;
new_obj->data.type = type; new_obj->type = type;
new_obj->data.name = name; new_obj->name = name;
new_obj->data.alloc_pc = pc; new_obj->alloc_pc = pc;
#if HAVE_GETTIMEOFDAY #if HAVE_GETTIMEOFDAY
gettimeofday (& new_obj->data.alloc_time, NULL); gettimeofday (& new_obj->alloc_time, NULL);
#endif #endif
#if LIBMUDFLAPTH #if LIBMUDFLAPTH
new_obj->data.alloc_thread = pthread_self (); new_obj->alloc_thread = pthread_self ();
#endif #endif
if (__mf_opts.backtrace > 0 && (type == __MF_TYPE_HEAP || type == __MF_TYPE_HEAP_I)) if (__mf_opts.backtrace > 0 && (type == __MF_TYPE_HEAP || type == __MF_TYPE_HEAP_I))
new_obj->data.alloc_backtrace_size = new_obj->alloc_backtrace_size =
__mf_backtrace (& new_obj->data.alloc_backtrace, __mf_backtrace (& new_obj->alloc_backtrace,
(void *) pc, 2); (void *) pc, 2);
__mf_link_object (new_obj); __mf_link_object (new_obj);
...@@ -1078,7 +1004,7 @@ __mfu_register (void *ptr, size_t sz, int type, const char *name) ...@@ -1078,7 +1004,7 @@ __mfu_register (void *ptr, size_t sz, int type, const char *name)
case mode_check: case mode_check:
{ {
__mf_object_tree_t *ovr_objs [1]; __mf_object_t *ovr_objs [1];
unsigned num_overlapping_objs; unsigned num_overlapping_objs;
uintptr_t low = (uintptr_t) ptr; uintptr_t low = (uintptr_t) ptr;
uintptr_t high = CLAMPSZ (ptr, sz); uintptr_t high = CLAMPSZ (ptr, sz);
...@@ -1087,118 +1013,30 @@ __mfu_register (void *ptr, size_t sz, int type, const char *name) ...@@ -1087,118 +1013,30 @@ __mfu_register (void *ptr, size_t sz, int type, const char *name)
/* Treat unknown size indication as 1. */ /* Treat unknown size indication as 1. */
if (UNLIKELY (sz == 0)) sz = 1; if (UNLIKELY (sz == 0)) sz = 1;
num_overlapping_objs = __mf_find_objects (low, high, ovr_objs, 1); /* Look for objects only of the same type. This will e.g. permit a registration
of a STATIC overlapping with a GUESS, and a HEAP with a NOACCESS. At
__mf_check time however harmful overlaps will be detected. */
num_overlapping_objs = __mf_find_objects2 (low, high, ovr_objs, 1, type);
/* Handle overlaps. */ /* Handle overlaps. */
if (UNLIKELY (num_overlapping_objs > 0)) if (UNLIKELY (num_overlapping_objs > 0))
{ {
__mf_object_tree_t *ovr_obj = ovr_objs[0]; __mf_object_t *ovr_obj = ovr_objs[0];
/* Quietly accept a single duplicate registration for /* Accept certain specific duplication pairs. */
static objects, since these may come from distinct if (((type == __MF_TYPE_STATIC) || (type == __MF_TYPE_GUESS))
compilation units. */ && ovr_obj->low == low
if (type == __MF_TYPE_STATIC && ovr_obj->high == high
&& ovr_obj->data.type == __MF_TYPE_STATIC && ovr_obj->type == type)
&& ovr_obj->data.low == low
&& ovr_obj->data.high == high)
{ {
/* do nothing */ /* Duplicate registration for static objects may come
VERBOSE_TRACE ("duplicate static reg %p-%p `%s'\n", from distinct compilation units. */
VERBOSE_TRACE ("harmless duplicate reg %p-%p `%s'\n",
(void *) low, (void *) high, (void *) low, (void *) high,
(ovr_obj->data.name ? ovr_obj->data.name : "")); (ovr_obj->name ? ovr_obj->name : ""));
break;
}
/* Quietly accept a single duplicate registration for
guess objects too. */
if (type == __MF_TYPE_GUESS &&
ovr_obj->data.type == __MF_TYPE_GUESS &&
ovr_obj->data.low == low &&
ovr_obj->data.high == high)
{
/* do nothing */
VERBOSE_TRACE ("duplicate guess reg %p-%p\n",
(void *) low, (void *) high);
break; break;
} }
/* Quietly accept new a guess registration that overlaps
at least one existing object. Trim it down to size. */
else if (type == __MF_TYPE_GUESS)
{
/* We need to split this new GUESS region into some
smaller ones. Or we may not need to insert it at
all if it is covered by the overlapping region. */
/* First, identify all the overlapping objects. */
__mf_object_tree_t **all_ovr_objs;
unsigned num_ovr_objs, n;
uintptr_t next_low;
DECLARE (void *, malloc, size_t c);
DECLARE (void, free, void *p);
all_ovr_objs = CALL_REAL (malloc, (sizeof (__mf_object_tree_t *) *
num_overlapping_objs));
if (all_ovr_objs == NULL) abort ();
num_ovr_objs = __mf_find_objects (low, high, all_ovr_objs,
num_overlapping_objs);
assert (num_ovr_objs == num_overlapping_objs);
VERBOSE_TRACE ("splitting guess %p-%p, # overlaps: %u\n",
(void *) low, (void *) high, num_ovr_objs);
/* Add GUESS regions between the holes: before each
overlapping region. */
next_low = low;
/* This makes use of the assumption that __mf_find_objects() returns
overlapping objects in an increasing sequence. */
for (n=0; n < min (num_ovr_objs, num_overlapping_objs); n++)
{
if (all_ovr_objs[n]->data.low > next_low) /* Gap? */
{
uintptr_t next_high = CLAMPSUB (all_ovr_objs[n]->data.low, 1);
__mfu_register ((void *) next_low, next_high-next_low+1,
__MF_TYPE_GUESS, name);
}
next_low = CLAMPADD (all_ovr_objs[n]->data.high, 1);
}
/* Add in any leftover room at the top. */
if (next_low <= high)
__mfu_register ((void *) next_low, high-next_low+1,
__MF_TYPE_GUESS, name);
/* XXX: future optimization: allow consecutive GUESS regions to
be glued together. */
CALL_REAL (free, all_ovr_objs);
return;
}
/* Quietly accept a non-GUESS region overlaying a GUESS
region. Handle it by removing the GUESS region
temporarily, then recursively adding this new object,
and then the GUESS back. The latter will be split up
by the recursive process above. */
else if (ovr_obj->data.type == __MF_TYPE_GUESS)
{
uintptr_t old_low = ovr_obj->data.low;
uintptr_t old_high = ovr_obj->data.high;
const char* old_name = ovr_obj->data.name;
/* Now to recursively remove the guess piece, and
reinsert them in the opposite order. Recursion
should bottom out if another non-GUESS overlapping
region is found for this new object (resulting in a
violation), or if no further overlap occurs. The
located GUESS region should end up being split up
in any case. */
__mfu_unregister ((void *) old_low, old_high-old_low+1);
__mfu_register ((void *) low, sz, type, name);
__mfu_register ((void *) old_low, old_high-old_low+1,
__MF_TYPE_GUESS, old_name);
return;
}
/* Alas, a genuine violation. */ /* Alas, a genuine violation. */
else else
{ {
...@@ -1208,16 +1046,11 @@ __mfu_register (void *ptr, size_t sz, int type, const char *name) ...@@ -1208,16 +1046,11 @@ __mfu_register (void *ptr, size_t sz, int type, const char *name)
__MF_VIOL_REGISTER); __MF_VIOL_REGISTER);
} }
} }
else /* No overlapping objects: AOK. */
/* No overlapping objects: AOK. */
else
{
__mf_insert_new_object (low, high, type, name, pc); __mf_insert_new_object (low, high, type, name, pc);
}
/* We could conceivably call __mf_check() here to prime the cache, /* We could conceivably call __mf_check() here to prime the cache,
but then the read_count/write_count field is not reliable. */ but then the read_count/write_count field is not reliable. */
break; break;
} }
} /* end switch (__mf_opts.mudflap_mode) */ } /* end switch (__mf_opts.mudflap_mode) */
...@@ -1225,25 +1058,25 @@ __mfu_register (void *ptr, size_t sz, int type, const char *name) ...@@ -1225,25 +1058,25 @@ __mfu_register (void *ptr, size_t sz, int type, const char *name)
void void
__mf_unregister (void *ptr, size_t sz) __mf_unregister (void *ptr, size_t sz, int type)
{ {
LOCKTH (); LOCKTH ();
BEGIN_RECURSION_PROTECT (); BEGIN_RECURSION_PROTECT ();
__mfu_unregister (ptr, sz); __mfu_unregister (ptr, sz, type);
END_RECURSION_PROTECT (); END_RECURSION_PROTECT ();
UNLOCKTH (); UNLOCKTH ();
} }
void void
__mfu_unregister (void *ptr, size_t sz) __mfu_unregister (void *ptr, size_t sz, int type)
{ {
DECLARE (void, free, void *ptr); DECLARE (void, free, void *ptr);
if (UNLIKELY (__mf_opts.sigusr1_report)) if (UNLIKELY (__mf_opts.sigusr1_report))
__mf_sigusr1_respond (); __mf_sigusr1_respond ();
TRACE ("unregister ptr=%p size=%lu\n", ptr, (unsigned long) sz); TRACE ("unregister ptr=%p size=%lu type=%x\n", ptr, (unsigned long) sz, type);
switch (__mf_opts.mudflap_mode) switch (__mf_opts.mudflap_mode)
{ {
...@@ -1266,23 +1099,28 @@ __mfu_unregister (void *ptr, size_t sz) ...@@ -1266,23 +1099,28 @@ __mfu_unregister (void *ptr, size_t sz)
case mode_check: case mode_check:
{ {
__mf_object_tree_t *old_obj = NULL; __mf_object_t *old_obj = NULL;
__mf_object_tree_t *del_obj = NULL; /* Object to actually delete. */ __mf_object_t *del_obj = NULL; /* Object to actually delete. */
__mf_object_tree_t *objs[1] = {NULL}; __mf_object_t *objs[1] = {NULL};
unsigned num_overlapping_objs; unsigned num_overlapping_objs;
/* Treat unknown size indication as 1. */ num_overlapping_objs = __mf_find_objects2 ((uintptr_t) ptr,
if (sz == 0) sz = 1; CLAMPSZ (ptr, sz), objs, 1, type);
num_overlapping_objs = __mf_find_objects ((uintptr_t) ptr, /* Special case for HEAP_I - see free & realloc hook. They don't
CLAMPSZ (ptr, sz), objs, 1); know whether the input region was HEAP or HEAP_I before
unmapping it. Here we give HEAP a try in case HEAP_I
failed. */
if ((type == __MF_TYPE_HEAP_I) && (num_overlapping_objs == 0))
{
num_overlapping_objs = __mf_find_objects2 ((uintptr_t) ptr,
CLAMPSZ (ptr, sz), objs, 1, __MF_TYPE_HEAP);
}
/* XXX: handle unregistration of big old GUESS region, that has since
been splintered. */
old_obj = objs[0]; old_obj = objs[0];
if (UNLIKELY ((num_overlapping_objs != 1) /* more than one overlap */
if (UNLIKELY (num_overlapping_objs != 1 || || ((sz == 0) ? 0 : (sz != (old_obj->high - old_obj->low + 1))) /* size mismatch */
(uintptr_t)ptr != old_obj->data.low)) /* XXX: what about sz? */ || ((uintptr_t) ptr != old_obj->low))) /* base mismatch */
{ {
__mf_violation (ptr, sz, __mf_violation (ptr, sz,
(uintptr_t) __builtin_return_address (0), NULL, (uintptr_t) __builtin_return_address (0), NULL,
...@@ -1291,45 +1129,44 @@ __mfu_unregister (void *ptr, size_t sz) ...@@ -1291,45 +1129,44 @@ __mfu_unregister (void *ptr, size_t sz)
} }
__mf_unlink_object (old_obj); __mf_unlink_object (old_obj);
__mf_uncache_object (& old_obj->data); __mf_uncache_object (old_obj);
/* Wipe buffer contents if desired. */ /* Wipe buffer contents if desired. */
if ((__mf_opts.wipe_stack && old_obj->data.type == __MF_TYPE_STACK) if ((__mf_opts.wipe_stack && old_obj->type == __MF_TYPE_STACK)
|| (__mf_opts.wipe_heap && (old_obj->data.type == __MF_TYPE_HEAP || (__mf_opts.wipe_heap && (old_obj->type == __MF_TYPE_HEAP
|| old_obj->data.type == __MF_TYPE_HEAP_I))) || old_obj->type == __MF_TYPE_HEAP_I)))
{ {
memset ((void *) old_obj->data.low, memset ((void *) old_obj->low,
0, 0,
(size_t) (old_obj->data.high - old_obj->data.low + 1)); (size_t) (old_obj->high - old_obj->low + 1));
} }
/* Manage the object cemetary. */ /* Manage the object cemetary. */
if (__mf_opts.persistent_count > 0 && if (__mf_opts.persistent_count > 0 &&
old_obj->data.type >= 0 && old_obj->type >= 0 &&
old_obj->data.type <= __MF_TYPE_MAX_CEM) old_obj->type <= __MF_TYPE_MAX_CEM)
{ {
old_obj->data.deallocated_p = 1; old_obj->deallocated_p = 1;
old_obj->left = old_obj->right = NULL; old_obj->dealloc_pc = (uintptr_t) __builtin_return_address (0);
old_obj->data.dealloc_pc = (uintptr_t) __builtin_return_address (0);
#if HAVE_GETTIMEOFDAY #if HAVE_GETTIMEOFDAY
gettimeofday (& old_obj->data.dealloc_time, NULL); gettimeofday (& old_obj->dealloc_time, NULL);
#endif #endif
#ifdef LIBMUDFLAPTH #ifdef LIBMUDFLAPTH
old_obj->data.dealloc_thread = pthread_self (); old_obj->dealloc_thread = pthread_self ();
#endif #endif
if (__mf_opts.backtrace > 0 && old_obj->data.type == __MF_TYPE_HEAP) if (__mf_opts.backtrace > 0 && old_obj->type == __MF_TYPE_HEAP)
old_obj->data.dealloc_backtrace_size = old_obj->dealloc_backtrace_size =
__mf_backtrace (& old_obj->data.dealloc_backtrace, __mf_backtrace (& old_obj->dealloc_backtrace,
NULL, 2); NULL, 2);
/* Encourage this object to be displayed again in current epoch. */ /* Encourage this object to be displayed again in current epoch. */
old_obj->data.description_epoch --; old_obj->description_epoch --;
/* Put this object into the cemetary. This may require this plot to /* Put this object into the cemetary. This may require this plot to
be recycled, and the previous resident to be designated del_obj. */ be recycled, and the previous resident to be designated del_obj. */
{ {
unsigned row = old_obj->data.type; unsigned row = old_obj->type;
unsigned plot = __mf_object_dead_head [row]; unsigned plot = __mf_object_dead_head [row];
del_obj = __mf_object_cemetary [row][plot]; del_obj = __mf_object_cemetary [row][plot];
...@@ -1344,14 +1181,14 @@ __mfu_unregister (void *ptr, size_t sz) ...@@ -1344,14 +1181,14 @@ __mfu_unregister (void *ptr, size_t sz)
if (__mf_opts.print_leaks) if (__mf_opts.print_leaks)
{ {
if ((old_obj->data.read_count + old_obj->data.write_count) == 0 && if ((old_obj->read_count + old_obj->write_count) == 0 &&
(old_obj->data.type == __MF_TYPE_HEAP (old_obj->type == __MF_TYPE_HEAP
|| old_obj->data.type == __MF_TYPE_HEAP_I)) || old_obj->type == __MF_TYPE_HEAP_I))
{ {
fprintf (stderr, fprintf (stderr,
"*******\n" "*******\n"
"mudflap warning: unaccessed registered object:\n"); "mudflap warning: unaccessed registered object:\n");
__mf_describe_object (& old_obj->data); __mf_describe_object (old_obj);
} }
} }
...@@ -1359,10 +1196,10 @@ __mfu_unregister (void *ptr, size_t sz) ...@@ -1359,10 +1196,10 @@ __mfu_unregister (void *ptr, size_t sz)
{ {
if (__mf_opts.backtrace > 0) if (__mf_opts.backtrace > 0)
{ {
CALL_REAL(free, del_obj->data.alloc_backtrace); CALL_REAL(free, del_obj->alloc_backtrace);
if (__mf_opts.persistent_count > 0) if (__mf_opts.persistent_count > 0)
{ {
CALL_REAL(free, del_obj->data.dealloc_backtrace); CALL_REAL(free, del_obj->dealloc_backtrace);
} }
} }
CALL_REAL(free, del_obj); CALL_REAL(free, del_obj);
...@@ -1380,75 +1217,6 @@ __mfu_unregister (void *ptr, size_t sz) ...@@ -1380,75 +1217,6 @@ __mfu_unregister (void *ptr, size_t sz)
} }
} }
/* ------------------------------------------------------------------------ */
/* __mf_validate_live_object_tree, _object_cemetary */
static void
__mf_validate_live_object_tree (__mf_object_tree_t *obj)
{
assert (obj != NULL);
if (__mf_opts.persistent_count > 0)
assert (! obj->data.deallocated_p);
if (obj->left)
{
assert (obj->left->data.high < obj->data.low);
__mf_validate_live_object_tree (obj->left);
}
if (obj->right)
{
assert (obj->right->data.low > obj->data.high);
__mf_validate_live_object_tree (obj->right);
}
}
static void
__mf_validate_object_cemetary ()
{
unsigned cls;
unsigned i;
for (cls = 0; cls <= __MF_TYPE_MAX_CEM; cls++)
{
assert (__mf_object_dead_head [cls] >= 0 &&
__mf_object_dead_head [cls] < __mf_opts.persistent_count);
for (i = 0; i < __mf_opts.persistent_count; i++)
{
__mf_object_tree_t *obj = __mf_object_cemetary [cls][i];
if (obj != NULL)
{
assert (obj->data.deallocated_p);
assert (obj->left == NULL);
assert (obj->right == NULL);
}
}
}
}
static void
__mf_validate_objects ()
{
if (__mf_object_root)
__mf_validate_live_object_tree (__mf_object_root);
if (__mf_opts.persistent_count > 0)
__mf_validate_object_cemetary ();
}
static void
__mf_age_tree (__mf_object_tree_t *obj)
{
assert (obj != NULL);
obj->data.liveness = obj->data.liveness >> 1;
if (obj->left)
__mf_age_tree (obj->left);
if (obj->right)
__mf_age_tree (obj->right);
}
struct tree_stats struct tree_stats
...@@ -1462,46 +1230,49 @@ struct tree_stats ...@@ -1462,46 +1230,49 @@ struct tree_stats
}; };
static void
__mf_tree_analyze (__mf_object_tree_t *obj, struct tree_stats* s) static int
__mf_adapt_cache_fn (splay_tree_node n, void *param)
{ {
assert (obj != NULL); __mf_object_t *obj = (__mf_object_t *) n->value;
struct tree_stats *s = (struct tree_stats *) param;
if (obj->left) assert (obj != NULL && s != NULL);
__mf_tree_analyze (obj->left, s);
/* Exclude never-accessed objects. */ /* Exclude never-accessed objects. */
if (obj->data.read_count + obj->data.write_count) if (obj->read_count + obj->write_count)
{ {
s->obj_count ++; s->obj_count ++;
s->total_size += (obj->data.high - obj->data.low + 1); s->total_size += (obj->high - obj->low + 1);
if (obj->data.liveness) if (obj->liveness)
{ {
unsigned i; unsigned i;
uintptr_t addr; uintptr_t addr;
VERBOSE_TRACE ("analyze low=%p live=%u name=`%s'\n", /* VERBOSE_TRACE ("analyze low=%p live=%u name=`%s'\n",
(void *) obj->data.low, obj->data.liveness, obj->data.name); (void *) obj->low, obj->liveness, obj->name); */
s->live_obj_count ++; s->live_obj_count ++;
s->total_weight += (double) obj->data.liveness; s->total_weight += (double) obj->liveness;
s->weighted_size += s->weighted_size +=
(double) (obj->data.high - obj->data.low + 1) * (double) (obj->high - obj->low + 1) *
(double) obj->data.liveness; (double) obj->liveness;
addr = obj->data.low; addr = obj->low;
for (i=0; i<sizeof(uintptr_t) * 8; i++) for (i=0; i<sizeof(uintptr_t) * 8; i++)
{ {
unsigned bit = addr & 1; unsigned bit = addr & 1;
s->weighted_address_bits[i][bit] += obj->data.liveness; s->weighted_address_bits[i][bit] += obj->liveness;
addr = addr >> 1; addr = addr >> 1;
} }
/* Age the liveness value. */
obj->liveness >>= 1;
} }
} }
if (obj->right) return 0;
__mf_tree_analyze (obj->right, s);
} }
...@@ -1517,8 +1288,12 @@ __mf_adapt_cache () ...@@ -1517,8 +1288,12 @@ __mf_adapt_cache ()
unsigned i; unsigned i;
memset (&s, 0, sizeof (s)); memset (&s, 0, sizeof (s));
if (__mf_object_root)
__mf_tree_analyze (__mf_object_root, & s); splay_tree_foreach (__mf_object_tree (__MF_TYPE_HEAP), __mf_adapt_cache_fn, (void *) & s);
splay_tree_foreach (__mf_object_tree (__MF_TYPE_HEAP_I), __mf_adapt_cache_fn, (void *) & s);
splay_tree_foreach (__mf_object_tree (__MF_TYPE_STACK), __mf_adapt_cache_fn, (void *) & s);
splay_tree_foreach (__mf_object_tree (__MF_TYPE_STATIC), __mf_adapt_cache_fn, (void *) & s);
splay_tree_foreach (__mf_object_tree (__MF_TYPE_GUESS), __mf_adapt_cache_fn, (void *) & s);
/* Maybe we're dealing with funny aging/adaptation parameters, or an /* Maybe we're dealing with funny aging/adaptation parameters, or an
empty tree. Just leave the cache alone in such cases, rather empty tree. Just leave the cache alone in such cases, rather
...@@ -1577,89 +1352,53 @@ __mf_adapt_cache () ...@@ -1577,89 +1352,53 @@ __mf_adapt_cache ()
/* __mf_find_object[s] */ /* __mf_find_object[s] */
/* Find overlapping live objecs between [low,high]. Return up to /* Find overlapping live objecs between [low,high]. Return up to
max_objs of their pointers in objs[]. Return total count of max_objs of their pointers in objs[]. Return total count of
overlaps (may exceed max_objs). */ overlaps (may exceed max_objs). */
/* XXX: track traversal statistics, like average depth, balance. */ unsigned
__mf_find_objects2 (uintptr_t ptr_low, uintptr_t ptr_high,
static unsigned __mf_object_t **objs, unsigned max_objs, int type)
__mf_find_objects_rec (uintptr_t low, uintptr_t high, __mf_object_tree_t **nodep,
__mf_object_tree_t **objs, unsigned max_objs)
{ {
unsigned count; unsigned count = 0;
__mf_object_tree_t *node = *nodep; splay_tree t = __mf_object_tree (type);
splay_tree_key k = (splay_tree_key) ptr_low;
assert (low <= high); int direction;
assert (max_objs == 0 || objs != NULL);
if (UNLIKELY (node == NULL)) return 0;
/* Traverse down left subtree. */
count = 0;
if (low < node->data.low)
count += __mf_find_objects_rec (low, min(high, node->data.low),
& node->left, objs, max_objs);
/* Track the used slots of objs[]. */ splay_tree_node n = splay_tree_lookup (t, k);
if (count < max_objs) /* An exact match for base address implies a hit. */
{ if (n != NULL)
objs += count;
max_objs -= count;
}
else
{ {
max_objs = 0; if (count < max_objs)
objs[count] = (__mf_object_t *) n->value;
count ++;
} }
/* Check for overlap with this node. */ /* Iterate left then right near this key value to find all overlapping objects. */
if (high >= node->data.low && low <= node->data.high) for (direction = 0; direction < 2; direction ++)
{ {
count ++; /* Reset search origin. */
if (max_objs > 0) /* Any room left? */ k = (splay_tree_key) ptr_low;
while (1)
{ {
objs[0] = node; __mf_object_t *obj;
objs ++;
max_objs --;
}
}
/* Traverse down right subtree. */ n = (direction == 0 ? splay_tree_predecessor (t, k) : splay_tree_successor (t, k));
if (high > node->data.high) if (n == NULL) break;
count += __mf_find_objects_rec (max (low, node->data.high), high, obj = (__mf_object_t *) n->value;
& node->right, objs, max_objs);
/* There is no need to manipulate objs/max_objs any further. */
if (! (obj->low <= ptr_high && obj->high >= ptr_low)) /* No overlap? */
break;
/* Rotate a child node up if its access count is higher. */ if (count < max_objs)
if (UNLIKELY ((node->left && node->left->data.liveness > node->data.liveness) && objs[count] = (__mf_object_t *) n->value;
((!node->right || (node->right && count ++;
node->left->data.liveness >
node->right->data.liveness)))))
{
__mf_object_tree_t *l = node->left;
__mf_object_tree_t *l_r = l->right;
*nodep = l; k = (splay_tree_key) obj->low;
l->right = node;
node->left = l_r;
__mf_treerot_left ++;
} }
else if (UNLIKELY ((node->right && node->right->data.liveness > node->data.liveness) &&
((!node->left || (node->left &&
node->right->data.liveness >
node->left->data.liveness)))))
{
__mf_object_tree_t *r = node->right;
__mf_object_tree_t *r_l = r->left;
*nodep = r;
r->left = node;
node->right = r_l;
__mf_treerot_right ++;
} }
return count; return count;
...@@ -1668,88 +1407,49 @@ __mf_find_objects_rec (uintptr_t low, uintptr_t high, __mf_object_tree_t **nodep ...@@ -1668,88 +1407,49 @@ __mf_find_objects_rec (uintptr_t low, uintptr_t high, __mf_object_tree_t **nodep
unsigned unsigned
__mf_find_objects (uintptr_t ptr_low, uintptr_t ptr_high, __mf_find_objects (uintptr_t ptr_low, uintptr_t ptr_high,
__mf_object_tree_t **objs, unsigned max_objs) __mf_object_t **objs, unsigned max_objs)
{ {
if (UNLIKELY(__mf_opts.internal_checking)) int type;
__mf_validate_objects (); unsigned count = 0;
return __mf_find_objects_rec (ptr_low, ptr_high, & __mf_object_root, objs, max_objs);
}
/* __mf_link_object */
static void
__mf_link_object2 (__mf_object_tree_t *ptr, __mf_object_tree_t **link)
{
__mf_object_tree_t *node = *link;
assert (ptr != NULL); /* Search each splay tree for overlaps. */
if (UNLIKELY(node == NULL)) for (type = __MF_TYPE_NOACCESS; type <= __MF_TYPE_GUESS; type++)
{ {
*link = ptr; unsigned c = __mf_find_objects2 (ptr_low, ptr_high, objs, max_objs, type);
return; if (c > max_objs)
{
max_objs = 0;
objs = NULL;
}
else /* NB: C may equal 0 */
{
max_objs -= c;
objs += c;
}
count += c;
} }
if (ptr->data.high < node->data.low) return count;
return __mf_link_object2 (ptr, & node->left);
else if (ptr->data.low > node->data.high)
return __mf_link_object2 (ptr, & node->right);
else
abort (); /* XXX: duplicate object */
} }
void
__mf_link_object (__mf_object_tree_t *ptr)
{
if (UNLIKELY(__mf_opts.internal_checking))
__mf_validate_objects ();
return __mf_link_object2 (ptr, & __mf_object_root);
}
/* __mf_unlink_object */ /* __mf_link_object */
static void static void
__mf_unlink_object2 (__mf_object_tree_t *ptr, __mf_object_tree_t **link) __mf_link_object (__mf_object_t *node)
{ {
__mf_object_tree_t *node = *link; splay_tree t = __mf_object_tree (node->type);
splay_tree_insert (t, (splay_tree_key) node->low, (splay_tree_value) node);
assert (ptr != NULL);
if (UNLIKELY(node == ptr))
{
static unsigned promote_left_p = 0;
promote_left_p = 1 - promote_left_p;
/* Alternate promoting the left & right subtrees. */
if (promote_left_p)
{
*link = ptr->left;
if (ptr->right != NULL)
__mf_link_object2 (ptr->right, link);
}
else
{
*link = ptr->right;
if (ptr->left != NULL)
__mf_link_object2 (ptr->left, link);
}
return;
}
if (ptr->data.high < node->data.low)
return __mf_unlink_object2 (ptr, & node->left);
else if (ptr->data.low > node->data.high)
return __mf_unlink_object2 (ptr, & node->right);
else
abort (); /* XXX: missing object; should fail more gracefully. */
} }
/* __mf_unlink_object */
static void static void
__mf_unlink_object (__mf_object_tree_t *node) __mf_unlink_object (__mf_object_t *node)
{ {
__mf_unlink_object2 (node, & __mf_object_root); splay_tree t = __mf_object_tree (node->type);
splay_tree_remove (t, (splay_tree_key) node->low);
} }
/* __mf_find_dead_objects */ /* __mf_find_dead_objects */
...@@ -1760,7 +1460,7 @@ __mf_unlink_object (__mf_object_tree_t *node) ...@@ -1760,7 +1460,7 @@ __mf_unlink_object (__mf_object_tree_t *node)
static unsigned static unsigned
__mf_find_dead_objects (uintptr_t low, uintptr_t high, __mf_find_dead_objects (uintptr_t low, uintptr_t high,
__mf_object_tree_t **objs, unsigned max_objs) __mf_object_t **objs, unsigned max_objs)
{ {
if (__mf_opts.persistent_count > 0) if (__mf_opts.persistent_count > 0)
{ {
...@@ -1786,14 +1486,14 @@ __mf_find_dead_objects (uintptr_t low, uintptr_t high, ...@@ -1786,14 +1486,14 @@ __mf_find_dead_objects (uintptr_t low, uintptr_t high,
plot = __mf_object_dead_head [row]; plot = __mf_object_dead_head [row];
for (i = 0; i <= recollection; i ++) for (i = 0; i <= recollection; i ++)
{ {
__mf_object_tree_t *obj; __mf_object_t *obj;
/* Look backward through row: it's a circular buffer. */ /* Look backward through row: it's a circular buffer. */
if (plot > 0) plot --; if (plot > 0) plot --;
else plot = __mf_opts.persistent_count - 1; else plot = __mf_opts.persistent_count - 1;
obj = __mf_object_cemetary [row][plot]; obj = __mf_object_cemetary [row][plot];
if (obj && obj->data.low <= high && obj->data.high >= low) if (obj && obj->low <= high && obj->high >= low)
{ {
/* Found an overlapping dead object! */ /* Found an overlapping dead object! */
if (count < max_objs) if (count < max_objs)
...@@ -1899,31 +1599,32 @@ __mf_describe_object (__mf_object_t *obj) ...@@ -1899,31 +1599,32 @@ __mf_describe_object (__mf_object_t *obj)
} }
} }
static unsigned
__mf_report_leaks (__mf_object_tree_t *node) static int
__mf_report_leaks_fn (splay_tree_node n, void *param)
{ {
/* The counter is amongst recursive calls, so __mf_object_t *node = (__mf_object_t *) n->value;
that cumulative numbers are printed below. */ unsigned *count = (unsigned *) param;
static unsigned count = 0;
if (count != NULL)
(*count) ++;
fprintf (stderr, "Leaked object %u:\n", (*count));
__mf_describe_object (node);
if (node == NULL) /* Reset */
{
count = 0;
return 0; return 0;
} }
/* Inorder traversal. */
if (node->left) static unsigned
__mf_report_leaks (node->left); __mf_report_leaks ()
if (node->data.type == __MF_TYPE_HEAP {
|| node->data.type == __MF_TYPE_HEAP_I) unsigned count = 0;
{
count ++; (void) splay_tree_foreach (__mf_object_tree (__MF_TYPE_HEAP),
fprintf (stderr, "Leaked object %u:\n", count); __mf_report_leaks_fn, & count);
__mf_describe_object (& node->data); (void) splay_tree_foreach (__mf_object_tree (__MF_TYPE_HEAP_I),
} __mf_report_leaks_fn, & count);
if (node->right)
__mf_report_leaks (node->right);
return count; return count;
} }
...@@ -1949,11 +1650,11 @@ __mfu_report () ...@@ -1949,11 +1650,11 @@ __mfu_report ()
fprintf (stderr, fprintf (stderr,
"*******\n" "*******\n"
"mudflap stats:\n" "mudflap stats:\n"
"calls to __mf_check: %lu rot: %lu/%lu\n" "calls to __mf_check: %lu\n"
" __mf_register: %lu [%luB, %luB, %luB, %luB, %luB]\n" " __mf_register: %lu [%luB, %luB, %luB, %luB, %luB]\n"
" __mf_unregister: %lu [%luB]\n" " __mf_unregister: %lu [%luB]\n"
" __mf_violation: [%lu, %lu, %lu, %lu, %lu]\n", " __mf_violation: [%lu, %lu, %lu, %lu, %lu]\n",
__mf_count_check, __mf_treerot_left, __mf_treerot_right, __mf_count_check,
__mf_count_register, __mf_count_register,
__mf_total_register_size[0], __mf_total_register_size[1], __mf_total_register_size[0], __mf_total_register_size[1],
__mf_total_register_size[2], __mf_total_register_size[3], __mf_total_register_size[2], __mf_total_register_size[3],
...@@ -2015,8 +1716,7 @@ __mfu_report () ...@@ -2015,8 +1716,7 @@ __mfu_report ()
/* Free up any remaining alloca()'d blocks. */ /* Free up any remaining alloca()'d blocks. */
__mf_wrap_alloca_indirect (0); __mf_wrap_alloca_indirect (0);
__mf_describe_object (NULL); /* Reset description epoch. */ __mf_describe_object (NULL); /* Reset description epoch. */
__mf_report_leaks (NULL); /* Reset cumulative count. */ l = __mf_report_leaks ();
l = __mf_report_leaks (__mf_object_root);
fprintf (stderr, "number of leaked objects: %u\n", l); fprintf (stderr, "number of leaked objects: %u\n", l);
} }
} }
...@@ -2184,7 +1884,7 @@ __mf_violation (void *ptr, size_t sz, uintptr_t pc, ...@@ -2184,7 +1884,7 @@ __mf_violation (void *ptr, size_t sz, uintptr_t pc,
for (dead_p = 0; dead_p <= 1; dead_p ++) /* for dead_p in 0 1 */ for (dead_p = 0; dead_p <= 1; dead_p ++) /* for dead_p in 0 1 */
{ {
enum {max_objs = 3}; /* magic */ enum {max_objs = 3}; /* magic */
__mf_object_tree_t *objs[max_objs]; __mf_object_t *objs[max_objs];
unsigned num_objs = 0; unsigned num_objs = 0;
uintptr_t s_low, s_high; uintptr_t s_low, s_high;
unsigned tries = 0; unsigned tries = 0;
...@@ -2214,7 +1914,7 @@ __mf_violation (void *ptr, size_t sz, uintptr_t pc, ...@@ -2214,7 +1914,7 @@ __mf_violation (void *ptr, size_t sz, uintptr_t pc,
for (i = 0; i < min (num_objs, max_objs); i++) for (i = 0; i < min (num_objs, max_objs); i++)
{ {
__mf_object_t *obj = & objs[i]->data; __mf_object_t *obj = objs[i];
uintptr_t low = (uintptr_t) ptr; uintptr_t low = (uintptr_t) ptr;
uintptr_t high = CLAMPSZ (ptr, sz); uintptr_t high = CLAMPSZ (ptr, sz);
unsigned before1 = (low < obj->low) ? obj->low - low : 0; unsigned before1 = (low < obj->low) ? obj->low - low : 0;
...@@ -2308,7 +2008,7 @@ __mf_watch_or_not (void *ptr, size_t sz, char flag) ...@@ -2308,7 +2008,7 @@ __mf_watch_or_not (void *ptr, size_t sz, char flag)
case mode_check: case mode_check:
{ {
__mf_object_tree_t **all_ovr_objs; __mf_object_t **all_ovr_objs;
unsigned obj_count; unsigned obj_count;
unsigned n; unsigned n;
DECLARE (void *, malloc, size_t c); DECLARE (void *, malloc, size_t c);
...@@ -2317,15 +2017,14 @@ __mf_watch_or_not (void *ptr, size_t sz, char flag) ...@@ -2317,15 +2017,14 @@ __mf_watch_or_not (void *ptr, size_t sz, char flag)
obj_count = __mf_find_objects (ptr_low, ptr_high, NULL, 0); obj_count = __mf_find_objects (ptr_low, ptr_high, NULL, 0);
VERBOSE_TRACE (" %u:", obj_count); VERBOSE_TRACE (" %u:", obj_count);
all_ovr_objs = CALL_REAL (malloc, (sizeof (__mf_object_tree_t *) * all_ovr_objs = CALL_REAL (malloc, (sizeof (__mf_object_t *) * obj_count));
obj_count));
if (all_ovr_objs == NULL) abort (); if (all_ovr_objs == NULL) abort ();
n = __mf_find_objects (ptr_low, ptr_high, all_ovr_objs, obj_count); n = __mf_find_objects (ptr_low, ptr_high, all_ovr_objs, obj_count);
assert (n == obj_count); assert (n == obj_count);
for (n = 0; n < obj_count; n ++) for (n = 0; n < obj_count; n ++)
{ {
__mf_object_t *obj = & (all_ovr_objs[n]->data); __mf_object_t *obj = all_ovr_objs[n];
VERBOSE_TRACE (" [%p]", (void *) obj); VERBOSE_TRACE (" [%p]", (void *) obj);
if (obj->watching_p != flag) if (obj->watching_p != flag)
...@@ -2438,3 +2137,28 @@ __assert_fail (const char *msg, const char *file, unsigned line, const char *fun ...@@ -2438,3 +2137,28 @@ __assert_fail (const char *msg, const char *file, unsigned line, const char *fun
#endif #endif
/* #include the generic splay tree implementation from libiberty here, to
ensure that it uses our memory allocation primitives. */
static void
splay_tree_free (void *p)
{
DECLARE (void, free, void *p);
CALL_REAL (free, p);
}
static void *
splay_tree_xmalloc (size_t s)
{
DECLARE (void *, malloc, size_t s);
return CALL_REAL (malloc, s);
}
#define free(z) splay_tree_free(z)
#define xmalloc(z) splay_tree_xmalloc(z)
#include "splay-tree.c"
...@@ -55,7 +55,8 @@ extern void __mf_check (void *ptr, size_t sz, int type, const char *location) ...@@ -55,7 +55,8 @@ extern void __mf_check (void *ptr, size_t sz, int type, const char *location)
__attribute((nothrow)); __attribute((nothrow));
extern void __mf_register (void *ptr, size_t sz, int type, const char *name) extern void __mf_register (void *ptr, size_t sz, int type, const char *name)
__attribute((nothrow)); __attribute((nothrow));
extern void __mf_unregister (void *ptr, size_t sz) __attribute((nothrow)); extern void __mf_unregister (void *ptr, size_t sz, int type)
__attribute((nothrow));
extern unsigned __mf_watch (void *ptr, size_t sz); extern unsigned __mf_watch (void *ptr, size_t sz);
extern unsigned __mf_unwatch (void *ptr, size_t sz); extern unsigned __mf_unwatch (void *ptr, size_t sz);
extern void __mf_report (); extern void __mf_report ();
......
...@@ -41,7 +41,7 @@ DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ ...@@ -41,7 +41,7 @@ DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
$(srcdir)/mfconfig.exp.in $(srcdir)/mfconfig.exp.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
$(top_srcdir)/configure.in $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4) $(ACLOCAL_M4)
mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
......
...@@ -6,7 +6,7 @@ int main () ...@@ -6,7 +6,7 @@ int main ()
/* One cannot redeclare __mf_lc_mask in proper C from instrumented /* One cannot redeclare __mf_lc_mask in proper C from instrumented
code, because of the way the instrumentation code emits its decls. */ code, because of the way the instrumentation code emits its decls. */
extern unsigned foo __asm__ ("__mf_lc_mask"); extern unsigned foo __asm__ ("__mf_lc_mask");
unsigned *bar = &foo; unsigned * volatile bar = &foo;
*bar = 4; *bar = 4;
return 0; return 0;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment