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},
...@@ -375,28 +364,28 @@ __mf_usage () ...@@ -375,28 +364,28 @@ __mf_usage ()
struct option *opt; struct option *opt;
fprintf (stderr, fprintf (stderr,
"This is a %s%sGCC \"mudflap\" memory-checked binary.\n" "This is a %s%sGCC \"mudflap\" memory-checked binary.\n"
"Mudflap is Copyright (C) 2002-2003 Free Software Foundation, Inc.\n" "Mudflap is Copyright (C) 2002-2003 Free Software Foundation, Inc.\n"
"\n" "\n"
"The mudflap code can be controlled by an environment variable:\n" "The mudflap code can be controlled by an environment variable:\n"
"\n" "\n"
"$ export MUDFLAP_OPTIONS='<options>'\n" "$ export MUDFLAP_OPTIONS='<options>'\n"
"$ <mudflapped_program>\n" "$ <mudflapped_program>\n"
"\n" "\n"
"where <options> is a space-separated list of \n" "where <options> is a space-separated list of \n"
"any of the following options. Use `-no-OPTION' to disable options.\n" "any of the following options. Use `-no-OPTION' to disable options.\n"
"\n", "\n",
#if HAVE_PTHREAD_H #if HAVE_PTHREAD_H
(threads_active_p ? "multi-threaded " : "single-threaded "), (threads_active_p ? "multi-threaded " : "single-threaded "),
#else #else
"", "",
#endif #endif
#if LIBMUDFLAPTH #if LIBMUDFLAPTH
"thread-aware " "thread-aware "
#else #else
"thread-unaware " "thread-unaware "
#endif #endif
); );
/* XXX: The multi-threaded thread-unaware combination is bad. */ /* XXX: The multi-threaded thread-unaware combination is bad. */
for (opt = options; opt->name; opt++) for (opt = options; opt->name; opt++)
...@@ -404,23 +393,23 @@ __mf_usage () ...@@ -404,23 +393,23 @@ __mf_usage ()
int default_p = (opt->value == * opt->target); int default_p = (opt->value == * opt->target);
switch (opt->type) switch (opt->type)
{ {
char buf[128]; char buf[128];
case set_option: case set_option:
fprintf (stderr, "-%-23.23s %s", opt->name, opt->description); fprintf (stderr, "-%-23.23s %s", opt->name, opt->description);
if (default_p) if (default_p)
fprintf (stderr, " [active]\n"); fprintf (stderr, " [active]\n");
else else
fprintf (stderr, "\n"); fprintf (stderr, "\n");
break; break;
case read_integer_option: case read_integer_option:
strncpy (buf, opt->name, 128); strncpy (buf, opt->name, 128);
strncpy (buf + strlen (opt->name), "=N", 2); strncpy (buf + strlen (opt->name), "=N", 2);
fprintf (stderr, "-%-23.23s %s", buf, opt->description); fprintf (stderr, "-%-23.23s %s", buf, opt->description);
fprintf (stderr, " [%d]\n", * opt->target); fprintf (stderr, " [%d]\n", * opt->target);
break; break;
default: abort(); default: abort();
} }
} }
fprintf (stderr, "\n"); fprintf (stderr, "\n");
...@@ -460,69 +449,69 @@ __mfu_set_options (const char *optstr) ...@@ -460,69 +449,69 @@ __mfu_set_options (const char *optstr)
case ' ': case ' ':
case '\t': case '\t':
case '\n': case '\n':
optstr++; optstr++;
break; break;
case '-': case '-':
if (*optstr+1) if (*optstr+1)
{ {
int negate = 0; int negate = 0;
optstr++; optstr++;
if (*optstr == '?' || if (*optstr == '?' ||
strncmp (optstr, "help", 4) == 0) strncmp (optstr, "help", 4) == 0)
{ {
/* Caller will print help and exit. */ /* Caller will print help and exit. */
return -1; return -1;
} }
if (strncmp (optstr, "no-", 3) == 0) if (strncmp (optstr, "no-", 3) == 0)
{ {
negate = 1; negate = 1;
optstr = & optstr[3]; optstr = & optstr[3];
} }
for (opts = options; opts->name; opts++) for (opts = options; opts->name; opts++)
{ {
if (strncmp (optstr, opts->name, strlen (opts->name)) == 0) if (strncmp (optstr, opts->name, strlen (opts->name)) == 0)
{ {
optstr += strlen (opts->name); optstr += strlen (opts->name);
assert (opts->target); assert (opts->target);
switch (opts->type) switch (opts->type)
{ {
case set_option: case set_option:
if (negate) if (negate)
*(opts->target) = 0; *(opts->target) = 0;
else else
*(opts->target) = opts->value; *(opts->target) = opts->value;
break; break;
case read_integer_option: case read_integer_option:
if (! negate && (*optstr == '=' && *(optstr+1))) if (! negate && (*optstr == '=' && *(optstr+1)))
{ {
optstr++; optstr++;
tmp = strtol (optstr, &nxt, 10); tmp = strtol (optstr, &nxt, 10);
if ((optstr != nxt) && (tmp != LONG_MAX)) if ((optstr != nxt) && (tmp != LONG_MAX))
{ {
optstr = nxt; optstr = nxt;
*(opts->target) = (int)tmp; *(opts->target) = (int)tmp;
} }
} }
else if (negate) else if (negate)
* opts->target = 0; * opts->target = 0;
break; break;
} }
} }
} }
} }
break; break;
default: default:
fprintf (stderr, fprintf (stderr,
"warning: unrecognized string '%s' in mudflap options\n", "warning: unrecognized string '%s' in mudflap options\n",
optstr); optstr);
optstr += strlen (optstr); optstr += strlen (optstr);
rc = -1; rc = -1;
break; break;
} }
} }
...@@ -567,7 +556,7 @@ __mf_resolve_single_dynamic (struct __mf_dynamic_entry *e) ...@@ -567,7 +556,7 @@ __mf_resolve_single_dynamic (struct __mf_dynamic_entry *e)
if (err) if (err)
{ {
fprintf (stderr, "mf: error in dlsym(\"%s\"): %s\n", fprintf (stderr, "mf: error in dlsym(\"%s\"): %s\n",
e->name, err); e->name, err);
abort (); abort ();
} }
if (! e->pointer) if (! e->pointer)
...@@ -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;
...@@ -628,10 +629,10 @@ void __mf_init () ...@@ -628,10 +629,10 @@ void __mf_init ()
{ {
int rc = __mfu_set_options (ov); int rc = __mfu_set_options (ov);
if (rc < 0) if (rc < 0)
{ {
__mf_usage (); __mf_usage ();
exit (1); exit (1);
} }
} }
/* Initialize to a non-zero description epoch. */ /* Initialize to a non-zero description epoch. */
...@@ -666,19 +667,19 @@ __wrap_main (int argc, char* argv[]) ...@@ -666,19 +667,19 @@ __wrap_main (int argc, char* argv[])
been_here = 1; been_here = 1;
__mf_register (argv, sizeof(char *)*(argc+1), __MF_TYPE_STATIC, "argv[]"); __mf_register (argv, sizeof(char *)*(argc+1), __MF_TYPE_STATIC, "argv[]");
for (i=0; i<argc; i++) for (i=0; i<argc; i++)
{ {
unsigned j = strlen (argv[i]); unsigned j = strlen (argv[i]);
__mf_register (argv[i], j+1, __MF_TYPE_STATIC, "argv element"); __mf_register (argv[i], j+1, __MF_TYPE_STATIC, "argv element");
} }
for (i=0; ; i++) for (i=0; ; i++)
{ {
char *e = environ[i]; char *e = environ[i];
unsigned j; unsigned j;
if (e == NULL) break; if (e == NULL) break;
j = strlen (environ[i]); j = strlen (environ[i]);
__mf_register (environ[i], j+1, __MF_TYPE_STATIC, "environ element"); __mf_register (environ[i], j+1, __MF_TYPE_STATIC, "environ element");
} }
__mf_register (environ, sizeof(char *)*(i+1), __MF_TYPE_STATIC, "environ[]"); __mf_register (environ, sizeof(char *)*(i+1), __MF_TYPE_STATIC, "environ[]");
__mf_register (& errno, sizeof (errno), __MF_TYPE_STATIC, "errno area"); __mf_register (& errno, sizeof (errno), __MF_TYPE_STATIC, "errno area");
...@@ -737,8 +738,8 @@ void __mfu_check (void *ptr, size_t sz, int type, const char *location) ...@@ -737,8 +738,8 @@ void __mfu_check (void *ptr, size_t sz, int type, const char *location)
__mf_sigusr1_respond (); __mf_sigusr1_respond ();
TRACE ("check ptr=%p b=%u size=%lu %s location=`%s'\n", TRACE ("check ptr=%p b=%u size=%lu %s location=`%s'\n",
ptr, entry_idx, (unsigned long)sz, ptr, entry_idx, (unsigned long)sz,
(type == 0 ? "read" : "write"), location); (type == 0 ? "read" : "write"), location);
switch (__mf_opts.mudflap_mode) switch (__mf_opts.mudflap_mode)
{ {
...@@ -756,192 +757,117 @@ void __mfu_check (void *ptr, size_t sz, int type, const char *location) ...@@ -756,192 +757,117 @@ void __mfu_check (void *ptr, size_t sz, int type, const char *location)
case mode_check: case mode_check:
{ {
unsigned heuristics = 0; unsigned heuristics = 0;
/* Advance aging/adaptation counters. */ /* Advance aging/adaptation counters. */
if (__mf_object_root) static unsigned adapt_count;
{ adapt_count ++;
static unsigned aging_count; if (UNLIKELY (__mf_opts.adapt_cache > 0 &&
static unsigned adapt_count; adapt_count > __mf_opts.adapt_cache))
aging_count ++; {
adapt_count ++; adapt_count = 0;
if (UNLIKELY (__mf_opts.tree_aging > 0 && __mf_adapt_cache ();
aging_count > __mf_opts.tree_aging)) }
{
aging_count = 0; /* Looping only occurs if heuristics were triggered. */
__mf_age_tree (__mf_object_root); while (judgement == 0)
} {
if (UNLIKELY (__mf_opts.adapt_cache > 0 && DECLARE (void, free, void *p);
adapt_count > __mf_opts.adapt_cache)) __mf_object_t* ovr_obj[1];
{ unsigned obj_count;
adapt_count = 0; __mf_object_t** all_ovr_obj = NULL;
__mf_adapt_cache (); __mf_object_t** dealloc_me = NULL;
} unsigned i;
}
/* Find all overlapping objects. Be optimistic that there is just one. */
/* Looping only occurs if heuristics were triggered. */ obj_count = __mf_find_objects (ptr_low, ptr_high, ovr_obj, 1);
while (judgement == 0) if (UNLIKELY (obj_count > 1))
{ {
__mf_object_tree_t* ovr_obj[1]; /* Allocate a real buffer and do the search again. */
unsigned obj_count; DECLARE (void *, malloc, size_t c);
unsigned n;
obj_count = __mf_find_objects (ptr_low, ptr_high, ovr_obj, 1); all_ovr_obj = CALL_REAL (malloc, (sizeof (__mf_object_t *) *
obj_count));
if (LIKELY (obj_count == 1)) /* A single hit! */ if (all_ovr_obj == NULL) abort ();
{ n = __mf_find_objects (ptr_low, ptr_high, all_ovr_obj, obj_count);
__mf_object_t *obj = & ovr_obj[0]->data; assert (n == obj_count);
assert (obj != NULL); dealloc_me = all_ovr_obj;
if (LIKELY (ptr_low >= obj->low && ptr_high <= obj->high)) }
{ else
/* XXX: hope for no overflow! */ {
if (type == __MF_CHECK_READ) all_ovr_obj = ovr_obj;
obj->read_count ++; dealloc_me = NULL;
else }
obj->write_count ++;
/* Update object statistics. */
obj->liveness ++; for (i = 0; i < obj_count; i++)
{
if (UNLIKELY (obj->type == __MF_TYPE_NOACCESS)) __mf_object_t *obj = all_ovr_obj[i];
judgement = -1; assert (obj != NULL);
else if (UNLIKELY (obj->watching_p)) if (type == __MF_CHECK_READ)
judgement = -2; /* trigger VIOL_WATCH */ obj->read_count ++;
else if (UNLIKELY (__mf_opts.check_initialization else
/* reading */ obj->write_count ++;
&& type == __MF_CHECK_READ obj->liveness ++;
/* not written */ }
&& obj->write_count == 0
/* uninitialized (heap) */ /* Iterate over the various objects. There are a number of special cases. */
&& obj->type == __MF_TYPE_HEAP)) for (i = 0; i < obj_count; i++)
judgement = -1; {
else __mf_object_t *obj = all_ovr_obj[i];
{
/* Valid access. */ /* Any __MF_TYPE_NOACCESS hit is bad. */
entry->low = obj->low; if (UNLIKELY (obj->type == __MF_TYPE_NOACCESS))
entry->high = obj->high; judgement = -1;
judgement = 1;
} /* Any object with a watch flag is bad. */
} if (UNLIKELY (obj->watching_p))
/* The object did not cover the entire accessed region. */ judgement = -2; /* trigger VIOL_WATCH */
}
else if (LIKELY (obj_count > 1)) /* A read from an uninitialized object is bad. */
{ if (UNLIKELY (__mf_opts.check_initialization
__mf_object_tree_t **all_ovr_objs; /* reading */
unsigned n; && type == __MF_CHECK_READ
DECLARE (void *, malloc, size_t c); /* not written */
DECLARE (void, free, void *p); && obj->write_count == 0
/* uninitialized (heap) */
all_ovr_objs = CALL_REAL (malloc, (sizeof (__mf_object_tree_t *) * && obj->type == __MF_TYPE_HEAP))
obj_count)); judgement = -1;
if (all_ovr_objs == NULL) abort (); }
n = __mf_find_objects (ptr_low, ptr_high, all_ovr_objs, obj_count);
assert (n == obj_count); /* We now know that the access spans one or more valid objects. */
if (LIKELY (judgement >= 0))
/* Confirm that accessed range is covered by first/last object. */ for (i = 0; i < obj_count; i++)
if (LIKELY ((ptr_low >= all_ovr_objs[0]->data.low) && {
(ptr_high <= all_ovr_objs[obj_count-1]->data.high))) __mf_object_t *obj = all_ovr_obj[i];
{
/* Presume valid access. */ /* Is this access entirely contained within this object? */
judgement = 1; if (LIKELY (ptr_low >= obj->low && ptr_high <= obj->high))
{
/* Confirm that intermediate objects are /* Valid access. */
contiguous and share a single name. Thus they entry->low = obj->low;
are likely split up GUESS regions, or mmap entry->high = obj->high;
pages. The idea of the name check is to judgement = 1;
prevent an oversize access to a }
stack-registered object (followed by some GUESS
type) from being accepted as a hit. */ /* XXX: Access runs off left or right side of this
for (n=0; n<obj_count-1; n++) object. That could be okay, if there are
{ other objects that fill in all the holes. */
__mf_object_t *obj = & (all_ovr_objs[n]->data); }
__mf_object_t *nextobj = & (all_ovr_objs[n+1]->data);
if (dealloc_me != NULL)
if (UNLIKELY (obj->type == __MF_TYPE_NOACCESS)) CALL_REAL (free, dealloc_me);
judgement = -1; /* Force error. */
/* If the judgment is still unknown at this stage, loop
if (UNLIKELY (judgement == 1 && around at most one more time. */
(obj->high + 1 != nextobj->low))) if (judgement == 0)
judgement = 0; /* Cancel presumption. */ {
if (heuristics++ < 2) /* XXX parametrize this number? */
if (UNLIKELY (judgement == 1 && judgement = __mf_heuristic_check (ptr_low, ptr_high);
(obj->name != nextobj->name))) else
judgement = 0; /* Cancel presumption. */ judgement = -1;
/* 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;
if (obj->write_count
|| obj->type == __MF_TYPE_HEAP_I
|| obj->type == __MF_TYPE_GUESS)
written_count ++;
}
/* Check for ALL pieces having been written-to.
XXX: should this be ANY instead? */
if (written_count != obj_count)
judgement = -1;
}
/* Fill out the cache with the bounds of the first
object and the last object that covers this
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 (judgement == 0)
{
if (heuristics++ < 2) /* XXX parametrize this number? */
judgement = __mf_heuristic_check (ptr_low, ptr_high);
else
judgement = -1;
}
}
} }
break; break;
...@@ -956,43 +882,43 @@ void __mfu_check (void *ptr, size_t sz, int type, const char *location) ...@@ -956,43 +882,43 @@ void __mfu_check (void *ptr, size_t sz, int type, const char *location)
__mf_count_check ++; __mf_count_check ++;
if (LIKELY (old_entry.low != entry->low || old_entry.high != entry->high)) if (LIKELY (old_entry.low != entry->low || old_entry.high != entry->high))
/* && (old_entry.low != 0) && (old_entry.high != 0)) */ /* && (old_entry.low != 0) && (old_entry.high != 0)) */
__mf_lookup_cache_reusecount [entry_idx] ++; __mf_lookup_cache_reusecount [entry_idx] ++;
} }
if (UNLIKELY (judgement < 0)) if (UNLIKELY (judgement < 0))
__mf_violation (ptr, sz, __mf_violation (ptr, sz,
(uintptr_t) __builtin_return_address (0), location, (uintptr_t) __builtin_return_address (0), location,
((judgement == -1) ? ((judgement == -1) ?
(type == __MF_CHECK_READ ? __MF_VIOL_READ : __MF_VIOL_WRITE) : (type == __MF_CHECK_READ ? __MF_VIOL_READ : __MF_VIOL_WRITE) :
__MF_VIOL_WATCH)); __MF_VIOL_WATCH));
} }
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);
return new_obj; return new_obj;
...@@ -1013,18 +939,18 @@ __mf_uncache_object (__mf_object_t *old_obj) ...@@ -1013,18 +939,18 @@ __mf_uncache_object (__mf_object_t *old_obj)
unsigned idx_high = __MF_CACHE_INDEX (high); unsigned idx_high = __MF_CACHE_INDEX (high);
unsigned i; unsigned i;
for (i = idx_low; i <= idx_high; i++) for (i = idx_low; i <= idx_high; i++)
{ {
struct __mf_cache *entry = & __mf_lookup_cache [i]; struct __mf_cache *entry = & __mf_lookup_cache [i];
/* NB: the "||" in the following test permits this code to /* NB: the "||" in the following test permits this code to
tolerate the situation introduced by __mf_check over tolerate the situation introduced by __mf_check over
contiguous objects, where a cache entry spans several contiguous objects, where a cache entry spans several
objects. */ objects. */
if (entry->low == low || entry->high == high) if (entry->low == low || entry->high == high)
{ {
entry->low = MAXPTR; entry->low = MAXPTR;
entry->high = MINPTR; entry->high = MINPTR;
} }
} }
} }
} }
...@@ -1044,14 +970,14 @@ void ...@@ -1044,14 +970,14 @@ void
__mfu_register (void *ptr, size_t sz, int type, const char *name) __mfu_register (void *ptr, size_t sz, int type, const char *name)
{ {
TRACE ("register ptr=%p size=%lu type=%x name='%s'\n", TRACE ("register ptr=%p size=%lu type=%x name='%s'\n",
ptr, (unsigned long) sz, type, name ? name : ""); ptr, (unsigned long) sz, type, name ? name : "");
if (__mf_opts.collect_stats) if (__mf_opts.collect_stats)
{ {
__mf_count_register ++; __mf_count_register ++;
__mf_total_register_size [(type < 0) ? 0 : __mf_total_register_size [(type < 0) ? 0 :
(type > __MF_TYPE_MAX) ? 0 : (type > __MF_TYPE_MAX) ? 0 :
type] += sz; type] += sz;
} }
if (UNLIKELY (__mf_opts.sigusr1_report)) if (UNLIKELY (__mf_opts.sigusr1_report))
...@@ -1064,7 +990,7 @@ __mfu_register (void *ptr, size_t sz, int type, const char *name) ...@@ -1064,7 +990,7 @@ __mfu_register (void *ptr, size_t sz, int type, const char *name)
case mode_violate: case mode_violate:
__mf_violation (ptr, sz, (uintptr_t) __builtin_return_address (0), NULL, __mf_violation (ptr, sz, (uintptr_t) __builtin_return_address (0), NULL,
__MF_VIOL_REGISTER); __MF_VIOL_REGISTER);
break; break;
case mode_populate: case mode_populate:
...@@ -1078,172 +1004,79 @@ __mfu_register (void *ptr, size_t sz, int type, const char *name) ...@@ -1078,172 +1004,79 @@ __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);
uintptr_t pc = (uintptr_t) __builtin_return_address (0); uintptr_t pc = (uintptr_t) __builtin_return_address (0);
/* 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
/* Handle overlaps. */ __mf_check time however harmful overlaps will be detected. */
if (UNLIKELY (num_overlapping_objs > 0)) num_overlapping_objs = __mf_find_objects2 (low, high, ovr_objs, 1, type);
{
__mf_object_tree_t *ovr_obj = ovr_objs[0]; /* Handle overlaps. */
if (UNLIKELY (num_overlapping_objs > 0))
/* Quietly accept a single duplicate registration for {
static objects, since these may come from distinct __mf_object_t *ovr_obj = ovr_objs[0];
compilation units. */
if (type == __MF_TYPE_STATIC /* Accept certain specific duplication pairs. */
&& ovr_obj->data.type == __MF_TYPE_STATIC if (((type == __MF_TYPE_STATIC) || (type == __MF_TYPE_GUESS))
&& ovr_obj->data.low == low && ovr_obj->low == low
&& ovr_obj->data.high == high) && ovr_obj->high == high
{ && ovr_obj->type == type)
/* do nothing */ {
VERBOSE_TRACE ("duplicate static reg %p-%p `%s'\n", /* Duplicate registration for static objects may come
(void *) low, (void *) high, from distinct compilation units. */
(ovr_obj->data.name ? ovr_obj->data.name : "")); VERBOSE_TRACE ("harmless duplicate reg %p-%p `%s'\n",
break; (void *) low, (void *) high,
} (ovr_obj->name ? ovr_obj->name : ""));
break;
/* Quietly accept a single duplicate registration for }
guess objects too. */
if (type == __MF_TYPE_GUESS && /* Alas, a genuine violation. */
ovr_obj->data.type == __MF_TYPE_GUESS && else
ovr_obj->data.low == low && {
ovr_obj->data.high == high) /* Two or more *real* mappings here. */
{ __mf_violation ((void *) ptr, sz,
/* do nothing */ (uintptr_t) __builtin_return_address (0), NULL,
VERBOSE_TRACE ("duplicate guess reg %p-%p\n", __MF_VIOL_REGISTER);
(void *) low, (void *) high); }
break; }
} else /* No overlapping objects: AOK. */
__mf_insert_new_object (low, high, type, name, pc);
/* Quietly accept new a guess registration that overlaps
at least one existing object. Trim it down to size. */ /* We could conceivably call __mf_check() here to prime the cache,
else if (type == __MF_TYPE_GUESS) but then the read_count/write_count field is not reliable. */
{ break;
/* 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. */
else
{
/* Two or more *real* mappings here. */
__mf_violation ((void *) ptr, sz,
(uintptr_t) __builtin_return_address (0), NULL,
__MF_VIOL_REGISTER);
}
}
/* No overlapping objects: AOK. */
else
{
__mf_insert_new_object (low, high, type, name, pc);
}
/* We could conceivably call __mf_check() here to prime the cache,
but then the read_count/write_count field is not reliable. */
break;
} }
} /* end switch (__mf_opts.mudflap_mode) */ } /* end switch (__mf_opts.mudflap_mode) */
} }
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)
{ {
...@@ -1252,8 +1085,8 @@ __mfu_unregister (void *ptr, size_t sz) ...@@ -1252,8 +1085,8 @@ __mfu_unregister (void *ptr, size_t sz)
case mode_violate: case mode_violate:
__mf_violation (ptr, sz, __mf_violation (ptr, sz,
(uintptr_t) __builtin_return_address (0), NULL, (uintptr_t) __builtin_return_address (0), NULL,
__MF_VIOL_UNREGISTER); __MF_VIOL_UNREGISTER);
break; break;
case mode_populate: case mode_populate:
...@@ -1266,109 +1099,113 @@ __mfu_unregister (void *ptr, size_t sz) ...@@ -1266,109 +1099,113 @@ __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
/* XXX: handle unregistration of big old GUESS region, that has since failed. */
been splintered. */ if ((type == __MF_TYPE_HEAP_I) && (num_overlapping_objs == 0))
old_obj = objs[0]; {
num_overlapping_objs = __mf_find_objects2 ((uintptr_t) ptr,
if (UNLIKELY (num_overlapping_objs != 1 || CLAMPSZ (ptr, sz), objs, 1, __MF_TYPE_HEAP);
(uintptr_t)ptr != old_obj->data.low)) /* XXX: what about sz? */ }
{
__mf_violation (ptr, sz, old_obj = objs[0];
(uintptr_t) __builtin_return_address (0), NULL, if (UNLIKELY ((num_overlapping_objs != 1) /* more than one overlap */
__MF_VIOL_UNREGISTER); || ((sz == 0) ? 0 : (sz != (old_obj->high - old_obj->low + 1))) /* size mismatch */
break; || ((uintptr_t) ptr != old_obj->low))) /* base mismatch */
} {
__mf_violation (ptr, sz,
__mf_unlink_object (old_obj); (uintptr_t) __builtin_return_address (0), NULL,
__mf_uncache_object (& old_obj->data); __MF_VIOL_UNREGISTER);
break;
/* Wipe buffer contents if desired. */ }
if ((__mf_opts.wipe_stack && old_obj->data.type == __MF_TYPE_STACK)
|| (__mf_opts.wipe_heap && (old_obj->data.type == __MF_TYPE_HEAP __mf_unlink_object (old_obj);
|| old_obj->data.type == __MF_TYPE_HEAP_I))) __mf_uncache_object (old_obj);
{
memset ((void *) old_obj->data.low, /* Wipe buffer contents if desired. */
0, if ((__mf_opts.wipe_stack && old_obj->type == __MF_TYPE_STACK)
(size_t) (old_obj->data.high - old_obj->data.low + 1)); || (__mf_opts.wipe_heap && (old_obj->type == __MF_TYPE_HEAP
} || old_obj->type == __MF_TYPE_HEAP_I)))
{
/* Manage the object cemetary. */ memset ((void *) old_obj->low,
if (__mf_opts.persistent_count > 0 && 0,
old_obj->data.type >= 0 && (size_t) (old_obj->high - old_obj->low + 1));
old_obj->data.type <= __MF_TYPE_MAX_CEM) }
{
old_obj->data.deallocated_p = 1; /* Manage the object cemetary. */
old_obj->left = old_obj->right = NULL; if (__mf_opts.persistent_count > 0 &&
old_obj->data.dealloc_pc = (uintptr_t) __builtin_return_address (0); old_obj->type >= 0 &&
old_obj->type <= __MF_TYPE_MAX_CEM)
{
old_obj->deallocated_p = 1;
old_obj->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];
__mf_object_cemetary [row][plot] = old_obj; __mf_object_cemetary [row][plot] = old_obj;
plot ++; plot ++;
if (plot == __mf_opts.persistent_count) plot = 0; if (plot == __mf_opts.persistent_count) plot = 0;
__mf_object_dead_head [row] = plot; __mf_object_dead_head [row] = plot;
} }
} }
else else
del_obj = old_obj; del_obj = old_obj;
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);
} }
} }
if (del_obj != NULL) /* May or may not equal old_obj. */ if (del_obj != NULL) /* May or may not equal old_obj. */
{ {
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);
} }
break; break;
} }
} /* end switch (__mf_opts.mudflap_mode) */ } /* end switch (__mf_opts.mudflap_mode) */
...@@ -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)
{
assert (obj != NULL);
if (obj->left) static int
__mf_tree_analyze (obj->left, s); __mf_adapt_cache_fn (splay_tree_node n, void *param)
{
__mf_object_t *obj = (__mf_object_t *) n->value;
struct tree_stats *s = (struct tree_stats *) param;
assert (obj != NULL && s != NULL);
/* 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
...@@ -1539,7 +1314,7 @@ __mf_adapt_cache () ...@@ -1539,7 +1314,7 @@ __mf_adapt_cache ()
float shoulder_factor = 0.7; /* Include slightly less popular bits too. */ float shoulder_factor = 0.7; /* Include slightly less popular bits too. */
float value = (float) s.weighted_address_bits[i][0] * (float) s.weighted_address_bits[i][1]; float value = (float) s.weighted_address_bits[i][0] * (float) s.weighted_address_bits[i][1];
if (value >= max_value * shoulder_factor) if (value >= max_value * shoulder_factor)
break; break;
} }
if (smoothed_new_shift < 0) smoothed_new_shift = __mf_lc_shift; if (smoothed_new_shift < 0) smoothed_new_shift = __mf_lc_shift;
/* Converge toward this slowly to reduce flapping. */ /* Converge toward this slowly to reduce flapping. */
...@@ -1558,9 +1333,9 @@ __mf_adapt_cache () ...@@ -1558,9 +1333,9 @@ __mf_adapt_cache ()
new_mask &= (LOOKUP_CACHE_SIZE_MAX - 1); new_mask &= (LOOKUP_CACHE_SIZE_MAX - 1);
VERBOSE_TRACE ("adapt cache obj=%u/%u sizes=%lu/%.0f/%.0f => " VERBOSE_TRACE ("adapt cache obj=%u/%u sizes=%lu/%.0f/%.0f => "
"util=%u%% m=%p s=%u\n", "util=%u%% m=%p s=%u\n",
s.obj_count, s.live_obj_count, s.total_size, s.total_weight, s.weighted_size, s.obj_count, s.live_obj_count, s.total_size, s.total_weight, s.weighted_size,
(unsigned)(cache_utilization*100.0), (void *) new_mask, new_shift); (unsigned)(cache_utilization*100.0), (void *) new_mask, new_shift);
/* We should reinitialize cache if its parameters have changed. */ /* We should reinitialize cache if its parameters have changed. */
if (new_mask != __mf_lc_mask || if (new_mask != __mf_lc_mask ||
...@@ -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[]. */
if (count < max_objs)
{
objs += count;
max_objs -= count;
}
else
{
max_objs = 0;
}
/* Check for overlap with this node. */ splay_tree_node n = splay_tree_lookup (t, k);
if (high >= node->data.low && low <= node->data.high) /* An exact match for base address implies a hit. */
if (n != NULL)
{ {
if (count < max_objs)
objs[count] = (__mf_object_t *) n->value;
count ++; count ++;
if (max_objs > 0) /* Any room left? */
{
objs[0] = node;
objs ++;
max_objs --;
}
} }
/* Traverse down right subtree. */ /* Iterate left then right near this key value to find all overlapping objects. */
if (high > node->data.high) for (direction = 0; direction < 2; direction ++)
count += __mf_find_objects_rec (max (low, node->data.high), high,
& node->right, objs, max_objs);
/* There is no need to manipulate objs/max_objs any further. */
/* Rotate a child node up if its access count is higher. */
if (UNLIKELY ((node->left && node->left->data.liveness > node->data.liveness) &&
((!node->right || (node->right &&
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;
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; /* Reset search origin. */
__mf_object_tree_t *r_l = r->left; k = (splay_tree_key) ptr_low;
*nodep = r; while (1)
r->left = node; {
node->right = r_l; __mf_object_t *obj;
__mf_treerot_right ++;
n = (direction == 0 ? splay_tree_predecessor (t, k) : splay_tree_successor (t, k));
if (n == NULL) break;
obj = (__mf_object_t *) n->value;
if (! (obj->low <= ptr_high && obj->high >= ptr_low)) /* No overlap? */
break;
if (count < max_objs)
objs[count] = (__mf_object_t *) n->value;
count ++;
k = (splay_tree_key) obj->low;
}
} }
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))
__mf_validate_objects ();
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; int type;
unsigned count = 0;
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)
{ {
...@@ -1772,43 +1472,43 @@ __mf_find_dead_objects (uintptr_t low, uintptr_t high, ...@@ -1772,43 +1472,43 @@ __mf_find_dead_objects (uintptr_t low, uintptr_t high,
assert (max_objs == 0 || objs != NULL); assert (max_objs == 0 || objs != NULL);
/* Widen the search from the most recent plots in each row, looking /* Widen the search from the most recent plots in each row, looking
backward in time. */ backward in time. */
recollection = 0; recollection = 0;
while (recollection < __mf_opts.persistent_count) while (recollection < __mf_opts.persistent_count)
{ {
count = 0; count = 0;
for (row = 0; row <= __MF_TYPE_MAX_CEM; row ++) for (row = 0; row <= __MF_TYPE_MAX_CEM; row ++)
{ {
unsigned plot; unsigned plot;
unsigned i; unsigned i;
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)
objs [count] = obj; objs [count] = obj;
count ++; count ++;
} }
} }
} }
if (count) if (count)
break; break;
/* Look farther back in time. */ /* Look farther back in time. */
recollection = (recollection * 2) + 1; recollection = (recollection * 2) + 1;
} }
return count; return count;
} else { } else {
...@@ -1831,39 +1531,39 @@ __mf_describe_object (__mf_object_t *obj) ...@@ -1831,39 +1531,39 @@ __mf_describe_object (__mf_object_t *obj)
if (__mf_opts.abbreviate && obj->description_epoch == epoch) if (__mf_opts.abbreviate && obj->description_epoch == epoch)
{ {
fprintf (stderr, fprintf (stderr,
"mudflap object %p: name=`%s'\n", "mudflap object %p: name=`%s'\n",
(void *) obj, (obj->name ? obj->name : "")); (void *) obj, (obj->name ? obj->name : ""));
return; return;
} }
else else
obj->description_epoch = epoch; obj->description_epoch = epoch;
fprintf (stderr, fprintf (stderr,
"mudflap object %p: name=`%s'\n" "mudflap object %p: name=`%s'\n"
"bounds=[%p,%p] size=%lu area=%s check=%ur/%uw liveness=%u%s\n" "bounds=[%p,%p] size=%lu area=%s check=%ur/%uw liveness=%u%s\n"
"alloc time=%lu.%06lu pc=%p" "alloc time=%lu.%06lu pc=%p"
#ifdef LIBMUDFLAPTH #ifdef LIBMUDFLAPTH
" thread=%u" " thread=%u"
#endif #endif
"\n", "\n",
(void *) obj, (obj->name ? obj->name : ""), (void *) obj, (obj->name ? obj->name : ""),
(void *) obj->low, (void *) obj->high, (void *) obj->low, (void *) obj->high,
(unsigned long) (obj->high - obj->low + 1), (unsigned long) (obj->high - obj->low + 1),
(obj->type == __MF_TYPE_NOACCESS ? "no-access" : (obj->type == __MF_TYPE_NOACCESS ? "no-access" :
obj->type == __MF_TYPE_HEAP ? "heap" : obj->type == __MF_TYPE_HEAP ? "heap" :
obj->type == __MF_TYPE_HEAP_I ? "heap-init" : obj->type == __MF_TYPE_HEAP_I ? "heap-init" :
obj->type == __MF_TYPE_STACK ? "stack" : obj->type == __MF_TYPE_STACK ? "stack" :
obj->type == __MF_TYPE_STATIC ? "static" : obj->type == __MF_TYPE_STATIC ? "static" :
obj->type == __MF_TYPE_GUESS ? "guess" : obj->type == __MF_TYPE_GUESS ? "guess" :
"unknown"), "unknown"),
obj->read_count, obj->write_count, obj->liveness, obj->read_count, obj->write_count, obj->liveness,
obj->watching_p ? " watching" : "", obj->watching_p ? " watching" : "",
obj->alloc_time.tv_sec, obj->alloc_time.tv_usec, obj->alloc_time.tv_sec, obj->alloc_time.tv_usec,
(void *) obj->alloc_pc (void *) obj->alloc_pc
#ifdef LIBMUDFLAPTH #ifdef LIBMUDFLAPTH
, (unsigned) obj->alloc_thread , (unsigned) obj->alloc_thread
#endif #endif
); );
if (__mf_opts.backtrace > 0) if (__mf_opts.backtrace > 0)
{ {
...@@ -1875,55 +1575,56 @@ __mf_describe_object (__mf_object_t *obj) ...@@ -1875,55 +1575,56 @@ __mf_describe_object (__mf_object_t *obj)
if (__mf_opts.persistent_count > 0) if (__mf_opts.persistent_count > 0)
{ {
if (obj->deallocated_p) if (obj->deallocated_p)
{ {
fprintf (stderr, "dealloc time=%lu.%06lu pc=%p" fprintf (stderr, "dealloc time=%lu.%06lu pc=%p"
#ifdef LIBMUDFLAPTH #ifdef LIBMUDFLAPTH
" thread=%u" " thread=%u"
#endif #endif
"\n", "\n",
obj->dealloc_time.tv_sec, obj->dealloc_time.tv_usec, obj->dealloc_time.tv_sec, obj->dealloc_time.tv_usec,
(void *) obj->dealloc_pc (void *) obj->dealloc_pc
#ifdef LIBMUDFLAPTH #ifdef LIBMUDFLAPTH
, (unsigned) obj->dealloc_thread , (unsigned) obj->dealloc_thread
#endif #endif
); );
if (__mf_opts.backtrace > 0) if (__mf_opts.backtrace > 0)
{ {
unsigned i; unsigned i;
for (i=0; i<obj->dealloc_backtrace_size; i++) for (i=0; i<obj->dealloc_backtrace_size; i++)
fprintf (stderr, " %s\n", obj->dealloc_backtrace[i]); fprintf (stderr, " %s\n", obj->dealloc_backtrace[i]);
} }
} }
} }
} }
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 (node == NULL) /* Reset */ if (count != NULL)
{ (*count) ++;
count = 0;
return 0;
}
/* Inorder traversal. */ fprintf (stderr, "Leaked object %u:\n", (*count));
if (node->left) __mf_describe_object (node);
__mf_report_leaks (node->left);
if (node->data.type == __MF_TYPE_HEAP return 0;
|| node->data.type == __MF_TYPE_HEAP_I) }
{
count ++;
fprintf (stderr, "Leaked object %u:\n", count); static unsigned
__mf_describe_object (& node->data); __mf_report_leaks ()
} {
if (node->right) unsigned count = 0;
__mf_report_leaks (node->right);
(void) splay_tree_foreach (__mf_object_tree (__MF_TYPE_HEAP),
__mf_report_leaks_fn, & count);
(void) splay_tree_foreach (__mf_object_tree (__MF_TYPE_HEAP_I),
__mf_report_leaks_fn, & count);
return count; return count;
} }
...@@ -1947,65 +1648,65 @@ __mfu_report () ...@@ -1947,65 +1648,65 @@ __mfu_report ()
if (__mf_opts.collect_stats) if (__mf_opts.collect_stats)
{ {
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],
__mf_total_register_size[4], /* XXX */ __mf_total_register_size[4], /* XXX */
__mf_count_unregister, __mf_total_unregister_size, __mf_count_unregister, __mf_total_unregister_size,
__mf_count_violation[0], __mf_count_violation[1], __mf_count_violation[0], __mf_count_violation[1],
__mf_count_violation[2], __mf_count_violation[3], __mf_count_violation[2], __mf_count_violation[3],
__mf_count_violation[4]); __mf_count_violation[4]);
fprintf (stderr, fprintf (stderr,
"calls with reentrancy: %lu\n", __mf_reentrancy); "calls with reentrancy: %lu\n", __mf_reentrancy);
#ifdef LIBMUDFLAPTH #ifdef LIBMUDFLAPTH
fprintf (stderr, fprintf (stderr,
" lock contention: %lu\n", __mf_lock_contention); " lock contention: %lu\n", __mf_lock_contention);
#endif #endif
/* Lookup cache stats. */ /* Lookup cache stats. */
{ {
unsigned i; unsigned i;
unsigned max_reuse = 0; unsigned max_reuse = 0;
unsigned num_used = 0; unsigned num_used = 0;
unsigned num_unused = 0; unsigned num_unused = 0;
for (i = 0; i < LOOKUP_CACHE_SIZE; i++) for (i = 0; i < LOOKUP_CACHE_SIZE; i++)
{ {
if (__mf_lookup_cache_reusecount[i]) if (__mf_lookup_cache_reusecount[i])
num_used ++; num_used ++;
else else
num_unused ++; num_unused ++;
if (max_reuse < __mf_lookup_cache_reusecount[i]) if (max_reuse < __mf_lookup_cache_reusecount[i])
max_reuse = __mf_lookup_cache_reusecount[i]; max_reuse = __mf_lookup_cache_reusecount[i];
} }
fprintf (stderr, "lookup cache slots used: %u unused: %u peak-reuse: %u\n", fprintf (stderr, "lookup cache slots used: %u unused: %u peak-reuse: %u\n",
num_used, num_unused, max_reuse); num_used, num_unused, max_reuse);
} }
{ {
unsigned live_count; unsigned live_count;
live_count = __mf_find_objects (MINPTR, MAXPTR, NULL, 0); live_count = __mf_find_objects (MINPTR, MAXPTR, NULL, 0);
fprintf (stderr, "number of live objects: %u\n", live_count); fprintf (stderr, "number of live objects: %u\n", live_count);
} }
if (__mf_opts.persistent_count > 0) if (__mf_opts.persistent_count > 0)
{ {
unsigned dead_count = 0; unsigned dead_count = 0;
unsigned row, plot; unsigned row, plot;
for (row = 0; row <= __MF_TYPE_MAX_CEM; row ++) for (row = 0; row <= __MF_TYPE_MAX_CEM; row ++)
for (plot = 0 ; plot < __mf_opts.persistent_count; plot ++) for (plot = 0 ; plot < __mf_opts.persistent_count; plot ++)
if (__mf_object_cemetary [row][plot] != 0) if (__mf_object_cemetary [row][plot] != 0)
dead_count ++; dead_count ++;
fprintf (stderr, " zombie objects: %u\n", dead_count); fprintf (stderr, " zombie objects: %u\n", dead_count);
} }
} }
if (__mf_opts.print_leaks && (__mf_opts.mudflap_mode == mode_check)) if (__mf_opts.print_leaks && (__mf_opts.mudflap_mode == mode_check))
{ {
...@@ -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);
} }
} }
...@@ -2074,7 +1774,7 @@ __mf_backtrace (char ***symbols, void *guess_pc, unsigned guess_omit_levels) ...@@ -2074,7 +1774,7 @@ __mf_backtrace (char ***symbols, void *guess_pc, unsigned guess_omit_levels)
if (guess_pc != NULL) if (guess_pc != NULL)
for (i=0; i<pc_array_size; i++) for (i=0; i<pc_array_size; i++)
if (pc_array [i] == guess_pc) if (pc_array [i] == guess_pc)
omitted_size = i; omitted_size = i;
if (omitted_size == 0) /* No match? */ if (omitted_size == 0) /* No match? */
if (pc_array_size > guess_omit_levels) if (pc_array_size > guess_omit_levels)
...@@ -2098,9 +1798,9 @@ __mf_backtrace (char ***symbols, void *guess_pc, unsigned guess_omit_levels) ...@@ -2098,9 +1798,9 @@ __mf_backtrace (char ***symbols, void *guess_pc, unsigned guess_omit_levels)
chars = (char *)buffer + (remaining_size * sizeof (char *)); chars = (char *)buffer + (remaining_size * sizeof (char *));
for (i = 0; i < remaining_size; i++) for (i = 0; i < remaining_size; i++)
{ {
pointers[i] = chars; pointers[i] = chars;
sprintf (chars, "[0x%p]", pc_array [omitted_size + i]); sprintf (chars, "[0x%p]", pc_array [omitted_size + i]);
chars = chars + perline; chars = chars + perline;
} }
*symbols = pointers; *symbols = pointers;
} }
...@@ -2115,20 +1815,20 @@ __mf_backtrace (char ***symbols, void *guess_pc, unsigned guess_omit_levels) ...@@ -2115,20 +1815,20 @@ __mf_backtrace (char ***symbols, void *guess_pc, unsigned guess_omit_levels)
void void
__mf_violation (void *ptr, size_t sz, uintptr_t pc, __mf_violation (void *ptr, size_t sz, uintptr_t pc,
const char *location, int type) const char *location, int type)
{ {
char buf [128]; char buf [128];
static unsigned violation_number; static unsigned violation_number;
DECLARE(void, free, void *ptr); DECLARE(void, free, void *ptr);
TRACE ("violation pc=%p location=%s type=%d ptr=%p size=%lu\n", TRACE ("violation pc=%p location=%s type=%d ptr=%p size=%lu\n",
(void *) pc, (void *) pc,
(location != NULL ? location : ""), type, ptr, (unsigned long) sz); (location != NULL ? location : ""), type, ptr, (unsigned long) sz);
if (__mf_opts.collect_stats) if (__mf_opts.collect_stats)
__mf_count_violation [(type < 0) ? 0 : __mf_count_violation [(type < 0) ? 0 :
(type > __MF_VIOL_WATCH) ? 0 : (type > __MF_VIOL_WATCH) ? 0 :
type] ++; type] ++;
/* Print out a basic warning message. */ /* Print out a basic warning message. */
if (__mf_opts.verbose_violations) if (__mf_opts.verbose_violations)
...@@ -2142,36 +1842,36 @@ __mf_violation (void *ptr, size_t sz, uintptr_t pc, ...@@ -2142,36 +1842,36 @@ __mf_violation (void *ptr, size_t sz, uintptr_t pc,
violation_number ++; violation_number ++;
fprintf (stderr, fprintf (stderr,
"*******\n" "*******\n"
"mudflap violation %u (%s): time=%lu.%06lu " "mudflap violation %u (%s): time=%lu.%06lu "
"ptr=%p size=%lu\npc=%p%s%s%s\n", "ptr=%p size=%lu\npc=%p%s%s%s\n",
violation_number, violation_number,
((type == __MF_VIOL_READ) ? "check/read" : ((type == __MF_VIOL_READ) ? "check/read" :
(type == __MF_VIOL_WRITE) ? "check/write" : (type == __MF_VIOL_WRITE) ? "check/write" :
(type == __MF_VIOL_REGISTER) ? "register" : (type == __MF_VIOL_REGISTER) ? "register" :
(type == __MF_VIOL_UNREGISTER) ? "unregister" : (type == __MF_VIOL_UNREGISTER) ? "unregister" :
(type == __MF_VIOL_WATCH) ? "watch" : "unknown"), (type == __MF_VIOL_WATCH) ? "watch" : "unknown"),
now.tv_sec, now.tv_usec, now.tv_sec, now.tv_usec,
(void *) ptr, (unsigned long)sz, (void *) pc, (void *) ptr, (unsigned long)sz, (void *) pc,
(location != NULL ? " location=`" : ""), (location != NULL ? " location=`" : ""),
(location != NULL ? location : ""), (location != NULL ? location : ""),
(location != NULL ? "'" : "")); (location != NULL ? "'" : ""));
if (__mf_opts.backtrace > 0) if (__mf_opts.backtrace > 0)
{ {
char ** symbols; char ** symbols;
unsigned i, num; unsigned i, num;
num = __mf_backtrace (& symbols, (void *) pc, 2); num = __mf_backtrace (& symbols, (void *) pc, 2);
/* Note: backtrace_symbols calls malloc(). But since we're in /* Note: backtrace_symbols calls malloc(). But since we're in
__mf_violation and presumably __mf_check, it'll detect __mf_violation and presumably __mf_check, it'll detect
recursion, and not put the new string into the database. */ recursion, and not put the new string into the database. */
for (i=0; i<num; i++) for (i=0; i<num; i++)
fprintf (stderr, " %s\n", symbols[i]); fprintf (stderr, " %s\n", symbols[i]);
/* Calling free() here would trigger a violation. */ /* Calling free() here would trigger a violation. */
CALL_REAL(free, symbols); CALL_REAL(free, symbols);
} }
...@@ -2183,56 +1883,56 @@ __mf_violation (void *ptr, size_t sz, uintptr_t pc, ...@@ -2183,56 +1883,56 @@ __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;
unsigned i; unsigned i;
s_low = (uintptr_t) ptr; s_low = (uintptr_t) ptr;
s_high = CLAMPSZ (ptr, sz); s_high = CLAMPSZ (ptr, sz);
while (tries < 16) /* magic */ while (tries < 16) /* magic */
{ {
if (dead_p) if (dead_p)
num_objs = __mf_find_dead_objects (s_low, s_high, objs, max_objs); num_objs = __mf_find_dead_objects (s_low, s_high, objs, max_objs);
else else
num_objs = __mf_find_objects (s_low, s_high, objs, max_objs); num_objs = __mf_find_objects (s_low, s_high, objs, max_objs);
if (num_objs) /* good enough */ if (num_objs) /* good enough */
break; break;
tries ++; tries ++;
/* XXX: tune this search strategy. It's too dependent on /* XXX: tune this search strategy. It's too dependent on
sz, which can vary from 1 to very big (when array index sz, which can vary from 1 to very big (when array index
checking) numbers. */ checking) numbers. */
s_low = CLAMPSUB (s_low, (sz * tries * tries)); s_low = CLAMPSUB (s_low, (sz * tries * tries));
s_high = CLAMPADD (s_high, (sz * tries * tries)); s_high = CLAMPADD (s_high, (sz * tries * tries));
} }
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;
unsigned after1 = (low > obj->high) ? low - obj->high : 0; unsigned after1 = (low > obj->high) ? low - obj->high : 0;
unsigned into1 = (high >= obj->low && low <= obj->high) ? low - obj->low : 0; unsigned into1 = (high >= obj->low && low <= obj->high) ? low - obj->low : 0;
unsigned before2 = (high < obj->low) ? obj->low - high : 0; unsigned before2 = (high < obj->low) ? obj->low - high : 0;
unsigned after2 = (high > obj->high) ? high - obj->high : 0; unsigned after2 = (high > obj->high) ? high - obj->high : 0;
unsigned into2 = (high >= obj->low && low <= obj->high) ? high - obj->low : 0; unsigned into2 = (high >= obj->low && low <= obj->high) ? high - obj->low : 0;
fprintf (stderr, "Nearby object %u: checked region begins %uB %s and ends %uB %s\n", fprintf (stderr, "Nearby object %u: checked region begins %uB %s and ends %uB %s\n",
num_helpful + i + 1, num_helpful + i + 1,
(before1 ? before1 : after1 ? after1 : into1), (before1 ? before1 : after1 ? after1 : into1),
(before1 ? "before" : after1 ? "after" : "into"), (before1 ? "before" : after1 ? "after" : "into"),
(before2 ? before2 : after2 ? after2 : into2), (before2 ? before2 : after2 ? after2 : into2),
(before2 ? "before" : after2 ? "after" : "into")); (before2 ? "before" : after2 ? "after" : "into"));
__mf_describe_object (obj); __mf_describe_object (obj);
} }
num_helpful += num_objs; num_helpful += num_objs;
} }
fprintf (stderr, "number of nearby objects: %u\n", num_helpful); fprintf (stderr, "number of nearby objects: %u\n", num_helpful);
...@@ -2296,7 +1996,7 @@ __mf_watch_or_not (void *ptr, size_t sz, char flag) ...@@ -2296,7 +1996,7 @@ __mf_watch_or_not (void *ptr, size_t sz, char flag)
unsigned count = 0; unsigned count = 0;
TRACE ("%s ptr=%p size=%lu\n", TRACE ("%s ptr=%p size=%lu\n",
(flag ? "watch" : "unwatch"), ptr, (unsigned long) sz); (flag ? "watch" : "unwatch"), ptr, (unsigned long) sz);
switch (__mf_opts.mudflap_mode) switch (__mf_opts.mudflap_mode)
{ {
...@@ -2308,38 +2008,37 @@ __mf_watch_or_not (void *ptr, size_t sz, char flag) ...@@ -2308,38 +2008,37 @@ __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);
DECLARE (void, free, void *p); DECLARE (void, free, void *p);
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];
__mf_object_t *obj = & (all_ovr_objs[n]->data);
VERBOSE_TRACE (" [%p]", (void *) obj);
VERBOSE_TRACE (" [%p]", (void *) obj); if (obj->watching_p != flag)
if (obj->watching_p != flag) {
{ obj->watching_p = flag;
obj->watching_p = flag; count ++;
count ++;
/* Remove object from cache, to ensure next access
/* Remove object from cache, to ensure next access goes through __mf_check(). */
goes through __mf_check(). */ if (flag)
if (flag) __mf_uncache_object (obj);
__mf_uncache_object (obj); }
} }
} CALL_REAL (free, all_ovr_objs);
CALL_REAL (free, all_ovr_objs);
} }
break; break;
} }
...@@ -2403,12 +2102,12 @@ write_itoa (int fd, unsigned n) ...@@ -2403,12 +2102,12 @@ write_itoa (int fd, unsigned n)
buf[bufsize-2-i] = digit + '0'; buf[bufsize-2-i] = digit + '0';
n /= 10; n /= 10;
if (n == 0) if (n == 0)
{ {
char *m = & buf [bufsize-2-i]; char *m = & buf [bufsize-2-i];
buf[bufsize-1] = '\0'; buf[bufsize-1] = '\0';
write (fd, m, strlen(m)); write (fd, m, strlen(m));
break; break;
} }
} }
} }
...@@ -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