From 2896fedf17d949fb218f68b419fa93e986163b2e Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Tue, 26 Jul 2011 15:52:56 +0100 Subject: [PATCH 4/8] Provide a hook to allow refcounting to be traced This is designed to be used from a wrapper function, partly to supply the same arguments every time for a particular class of object, and partly to provide a more specific gdb breakpoint. It has several purposes: * when under gdb, provide a function which can be used in breakpoints * when not under valgrind and DBUS_MESSAGE_TRACE=1 is set, emit a _dbus_verbose when a message's refcount changes * when under valgrind and DBUS_MESSAGE_TRACE=1 is set, emit a VALGRIND_PRINTF_BACKTRACE when a message's refcount changes, which lets you see the complete history of each message to track down reference leaks Compile-time support is currently conditional on DBUS_ENABLE_VERBOSE_MODE, but could be separated out if desired. --- dbus/dbus-internals.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++ dbus/dbus-internals.h | 8 ++++++ 2 files changed, 75 insertions(+), 0 deletions(-) diff --git a/dbus/dbus-internals.c b/dbus/dbus-internals.c index fcea079..8fccee7 100644 --- a/dbus/dbus-internals.c +++ b/dbus/dbus-internals.c @@ -26,6 +26,7 @@ #include "dbus-protocol.h" #include "dbus-marshal-basic.h" #include "dbus-test.h" +#include "dbus-valgrind-internal.h" #include #include #include @@ -465,6 +466,72 @@ _dbus_verbose_reset_real (void) verbose_initted = FALSE; } +void +_dbus_trace_ref (const char *obj_name, + void *obj, + int old_refcount, + int new_refcount, + const char *why, + const char *env_var, + int *enabled) +{ + _dbus_assert (obj_name != NULL); + _dbus_assert (obj != NULL); + _dbus_assert (old_refcount >= -1); + _dbus_assert (new_refcount >= -1); + + if (old_refcount == -1) + { + _dbus_assert (new_refcount == -1); + } + else + { + _dbus_assert (new_refcount >= 0); + _dbus_assert (old_refcount >= 0); + _dbus_assert (old_refcount > 0 || new_refcount > 0); + } + + _dbus_assert (why != NULL); + _dbus_assert (env_var != NULL); + _dbus_assert (enabled != NULL); + + if (*enabled < 0) + { + const char *s = _dbus_getenv (env_var); + + *enabled = FALSE; + + if (s && *s) + { + if (*s == '0') + *enabled = FALSE; + else if (*s == '1') + *enabled = TRUE; + else + _dbus_warn ("%s should be 0 or 1 if set, not '%s'", env_var, s); + } + } + + if (*enabled) + { + if (old_refcount == -1) + { + VALGRIND_PRINTF_BACKTRACE ("%s %p ref stolen (%s)", + obj_name, obj, why); + _dbus_verbose ("%s %p ref stolen (%s)", + obj_name, obj, why); + } + else + { + VALGRIND_PRINTF_BACKTRACE ("%s %p %d -> %d refs (%s)", + obj_name, obj, + old_refcount, new_refcount, why); + _dbus_verbose ("%s %p %d -> %d refs (%s)", + obj_name, obj, old_refcount, new_refcount, why); + } + } +} + #endif /* DBUS_ENABLE_VERBOSE_MODE */ /** diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h index 06e6c16..cabc9f6 100644 --- a/dbus/dbus-internals.h +++ b/dbus/dbus-internals.h @@ -118,6 +118,14 @@ static void _dbus_verbose(const char * x,...) {;} # define _dbus_is_verbose() FALSE #endif /* !DBUS_ENABLE_VERBOSE_MODE */ +void _dbus_trace_ref (const char *obj_name, + void *obj, + int old_refcount, + int new_refcount, + const char *why, + const char *env_var, + int *enabled); + const char* _dbus_strerror (int error_number); #ifdef DBUS_DISABLE_ASSERT -- 1.7.6.3