Index: configure.in =================================================================== --- configure.in (revision 61828) +++ configure.in (working copy) @@ -2232,6 +2232,19 @@ then fi AC_MSG_RESULT($with_pymalloc) +# Check for Valgrind support +AC_MSG_CHECKING([for --with-valgrind]) +AC_ARG_WITH([valgrind], + AC_HELP_STRING([--with-valgrind], [Enable Valgrind support]),, + with_valgrind=no) +AC_MSG_RESULT([$with_valgrind]) +if test "$with_valgrind" != no; then + AC_CHECK_HEADER([valgrind/valgrind.h], + [AC_DEFINE([WITH_VALGRIND], 1, [Define if you want pymalloc to be disabled when running under valgrind])], + [AC_MSG_ERROR([Valgrind support requested but headers not available])] + ) +fi + # Check for --with-wctype-functions AC_MSG_CHECKING(for --with-wctype-functions) AC_ARG_WITH(wctype-functions, Index: Objects/obmalloc.c =================================================================== --- Objects/obmalloc.c (revision 61828) +++ Objects/obmalloc.c (working copy) @@ -2,6 +2,21 @@ #ifdef WITH_PYMALLOC +#ifdef WITH_VALGRIND +#include + +/* If we're using GCC, use __builtin_expect() to reduce overhead of + the valgrind checks */ +#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__) +# define UNLIKELY(value) __builtin_expect((value), 0) +#else +# define UNLIKELY(value) (value) +#endif + +/* -1 indicates that we haven't checked that we're running on valgrind yet. */ +static int running_on_valgrind = -1; +#endif + /* An object allocator for Python. Here is an introduction to the layers of the Python memory architecture, @@ -726,6 +741,13 @@ PyObject_Malloc(size_t nbytes) poolp next; uint size; +#ifdef WITH_VALGRIND + if (UNLIKELY(running_on_valgrind == -1)) + running_on_valgrind = RUNNING_ON_VALGRIND; + if (UNLIKELY(running_on_valgrind)) + goto redirect; +#endif + /* * This implicitly redirects malloc(0). */ @@ -916,6 +938,11 @@ PyObject_Free(void *p) if (p == NULL) /* free(NULL) has no effect */ return; +#ifdef WITH_VALGRIND + if (UNLIKELY(running_on_valgrind > 0)) + goto redirect; +#endif + pool = POOL_ADDR(p); if (Py_ADDRESS_IN_RANGE(p, pool)) { /* We allocated this address. */ @@ -1110,6 +1137,7 @@ PyObject_Free(void *p) return; } +redirect: /* We didn't allocate this address. */ free(p); } @@ -1130,6 +1158,12 @@ PyObject_Realloc(void *p, size_t nbytes) if (p == NULL) return PyObject_Malloc(nbytes); +#ifdef WITH_VALGRIND + /* Treat running_on_valgrind == -1 the same as 0 */ + if (UNLIKELY(running_on_valgrind > 0)) + goto redirect; +#endif + pool = POOL_ADDR(p); if (Py_ADDRESS_IN_RANGE(p, pool)) { /* We're in charge of this block */ @@ -1157,6 +1191,7 @@ PyObject_Realloc(void *p, size_t nbytes) } return bp; } + redirect: /* We're not managing this block. If nbytes <= * SMALL_REQUEST_THRESHOLD, it's tempting to try to take over this * block. However, if we do, we need to copy the valid data from Index: Misc/NEWS =================================================================== --- Misc/NEWS (revision 61828) +++ Misc/NEWS (working copy) @@ -60,6 +60,11 @@ Core and builtins - Issue #2143: Fix embedded readline() hang on SSL socket EOF. +- Issue #2422: When compiled with the ``--with-valgrind`` option, the + pymalloc allocator will be automatically disabled when running under + Valgrind. This gives improved memory leak detection when running + under Valgrind, while taking advantage of pymalloc at other times. + Library ------- Index: pyconfig.h.in =================================================================== --- pyconfig.h.in (revision 61828) +++ pyconfig.h.in (working copy) @@ -958,6 +958,9 @@ /* Define to profile with the Pentium timestamp counter */ #undef WITH_TSC +/* Define if you want pymalloc to be disabled when running under valgrind */ +#undef WITH_VALGRIND + /* Define to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX).