--------------------- PatchSet 7577 Date: 2006/04/29 00:22:20 Author: hno Branch: valgrind Tag: (none) Log: valgrind memory debugging suppor, and some sanity checking of MemPool to trap objects allocated from one pool and freed to another. Members: configure.in:1.81->1.81.2.1 src/MemPool.c:1.9->1.9.2.1 src/cbdata.c:1.17->1.17.2.1 src/main.c:1.42->1.42.2.1 src/mem.c:1.22->1.22.2.1 src/squid.h:1.23->1.23.2.1 src/structs.h:1.73->1.73.2.1 Index: squid/configure.in =================================================================== RCS file: /cvsroot/squid-sf//squid/configure.in,v retrieving revision 1.81 retrieving revision 1.81.2.1 diff -u -r1.81 -r1.81.2.1 --- squid/configure.in 28 Apr 2006 11:10:45 -0000 1.81 +++ squid/configure.in 29 Apr 2006 00:22:20 -0000 1.81.2.1 @@ -3,7 +3,7 @@ dnl dnl Duane Wessels, wessels@nlanr.net, February 1996 (autoconf v2.9) dnl -dnl $Id: configure.in,v 1.81 2006/04/28 11:10:45 squidadm Exp $ +dnl $Id: configure.in,v 1.81.2.1 2006/04/29 00:22:20 hno Exp $ dnl dnl dnl @@ -11,7 +11,7 @@ AC_CONFIG_AUX_DIR(cfgaux) AM_INIT_AUTOMAKE(squid, 2.6.DEVEL-CVS) AM_CONFIG_HEADER(include/autoconf.h) -AC_REVISION($Revision: 1.81 $)dnl +AC_REVISION($Revision: 1.81.2.1 $)dnl AC_PREFIX_DEFAULT(/usr/local/squid) AM_MAINTAINER_MODE @@ -250,6 +250,35 @@ dnl fi dnl ]) +valgrind= +AC_ARG_WITH(valgrind-debug, +[ --with-valgrind-debug Include debug instrumentation for use with valgrind], +[ case $withval in + yes) + valgrind=1 + ;; + no) + valgrind= + ;; + *) + CPPFLAGS="$CPPFLAGS -I${enableval}/include" + valgrind=1 + ;; + esac + if test $valgrind; then + AC_DEFINE(WITH_VALGRIND, 1, [Valgrind memory debugger support]) + echo "Valgrind debug support enabled" + fi +]) + +valgrind= +AC_ARG_ENABLE(mempool-debug, +[ --enable-mempool-debug Include MemPool debug verifications]) +if test "$enable_mempool_debug" = yes; then + AC_DEFINE(DEBUG_MEMPOOL, 1, [MemPool debug verifications]) + echo "Mempool debug checks enabled" +fi + AC_ARG_ENABLE(xmalloc-statistics, [ --enable-xmalloc-statistics Show malloc statistics in status page], Index: squid/src/MemPool.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/MemPool.c,v retrieving revision 1.9 retrieving revision 1.9.2.1 diff -u -r1.9 -r1.9.2.1 --- squid/src/MemPool.c 28 Apr 2006 11:10:50 -0000 1.9 +++ squid/src/MemPool.c 29 Apr 2006 00:22:20 -0000 1.9.2.1 @@ -1,6 +1,6 @@ /* - * $Id: MemPool.c,v 1.9 2006/04/28 11:10:50 squidadm Exp $ + * $Id: MemPool.c,v 1.9.2.1 2006/04/29 00:22:20 hno Exp $ * * DEBUG: section 63 Low Level Memory Pool Management * AUTHOR: Alex Rousskov @@ -83,9 +83,15 @@ { size_t new_pool_limit = mem_idle_limit; /* set to configured value first */ +#if LEAK_CHECK_MODE #if PURIFY - debug(63, 1) ("Disabling Memory pools under purify\n"); - Config.onoff.mem_pools = 0; + if (1) { +#else + if (RUNNING_ON_VALGRIND) { +#endif + debug(63, 1) ("Disabling Memory pools for accurate leak checks\n"); + Config.onoff.mem_pools = 0; + } #endif if (!Config.onoff.mem_pools) new_pool_limit = 0; @@ -209,6 +215,9 @@ assert(label && obj_size); pool->label = label; pool->obj_size = obj_size; +#if DEBUG_MEMPOOL + pool->real_obj_size = (obj_size & 7) ? (obj_size | 7) + 1 : obj_size ; +#endif stackInit(&pool->pstack); /* other members are set to 0 */ stackPush(&Pools, pool); @@ -230,9 +239,19 @@ xfree(pool); } +#if DEBUG_MEMPOOL +#define MEMPOOL_COOKIE(p) ((void *)((unsigned long)(p) ^ 0xDEADBEEF)) +struct mempool_cookie { + MemPool *pool; + void *cookie; +}; + +#endif + void * memPoolAlloc(MemPool * pool) { + void *obj; assert(pool); memMeterInc(pool->meter.inuse); gb_inc(&pool->meter.total, 1); @@ -246,13 +265,38 @@ memMeterDel(TheMeter.idle, pool->obj_size); gb_inc(&pool->meter.saved, 1); gb_inc(&TheMeter.saved, pool->obj_size); - return stackPop(&pool->pstack); + obj = stackPop(&pool->pstack); +#if DEBUG_MEMPOOL + (void) VALGRIND_MAKE_READABLE(obj, pool->real_obj_size + sizeof(struct mempool_cookie)); +#else + (void) VALGRIND_MAKE_READABLE(obj, pool->obj_size); +#endif +#if DEBUG_MEMPOOL + { + struct mempool_cookie *cookie = (void *) (((unsigned char *) obj) + pool->real_obj_size); + assert(cookie->cookie == MEMPOOL_COOKIE(obj)); + assert(cookie->pool == pool); + (void) VALGRIND_MAKE_NOACCESS(cookie, sizeof(cookie)); + } +#endif } else { assert(!pool->meter.idle.level); memMeterInc(pool->meter.alloc); memMeterAdd(TheMeter.alloc, pool->obj_size); - return xcalloc(1, pool->obj_size); +#if DEBUG_MEMPOOL + { + struct mempool_cookie *cookie; + obj = xcalloc(1, pool->real_obj_size + sizeof(struct mempool_cookie)); + cookie = (struct mempool_cookie *)(((unsigned char *) obj) + pool->real_obj_size); + cookie->cookie = MEMPOOL_COOKIE(obj); + cookie->pool = pool; + (void) VALGRIND_MAKE_NOACCESS(cookie, sizeof(cookie)); + } +#else + obj = xcalloc(1, pool->obj_size); +#endif } + return obj; } void @@ -262,10 +306,24 @@ memMeterDec(pool->meter.inuse); memMeterDel(TheMeter.inuse, pool->obj_size); mem_pool_free_calls++; + (void) VALGRIND_CHECK_READABLE(obj, pool->obj_size); +#if DEBUG_MEMPOOL + { + struct mempool_cookie *cookie = (void *) (((unsigned char *) obj) + pool->real_obj_size); + (void) VALGRIND_MAKE_READABLE(cookie, sizeof(cookie)); + assert(cookie->cookie == MEMPOOL_COOKIE(obj)); + assert(cookie->pool == pool); + } +#endif if (TheMeter.idle.level + pool->obj_size <= mem_idle_limit) { memMeterInc(pool->meter.idle); memMeterAdd(TheMeter.idle, pool->obj_size); memset(obj, 0, pool->obj_size); +#if DEBUG_MEMPOOL + (void) VALGRIND_MAKE_NOACCESS(obj, pool->real_obj_size + sizeof(struct mempool_cookie)); +#else + (void) VALGRIND_MAKE_NOACCESS(obj, pool->obj_size); +#endif stackPush(&pool->pstack, obj); } else { memMeterDec(pool->meter.alloc); Index: squid/src/cbdata.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/cbdata.c,v retrieving revision 1.17 retrieving revision 1.17.2.1 diff -u -r1.17 -r1.17.2.1 --- squid/src/cbdata.c 28 Apr 2006 11:10:50 -0000 1.17 +++ squid/src/cbdata.c 29 Apr 2006 00:22:20 -0000 1.17.2.1 @@ -1,6 +1,6 @@ /* - * $Id: cbdata.c,v 1.17 2006/04/28 11:10:50 squidadm Exp $ + * $Id: cbdata.c,v 1.17.2.1 2006/04/29 00:22:20 hno Exp $ * * DEBUG: section 45 Callback Data Registry * ORIGINAL AUTHOR: Duane Wessels @@ -66,9 +66,16 @@ #include "squid.h" +#if WITH_VALGRIND +#define HASHED_CBDATA 1 +#endif + static int cbdataCount = 0; typedef struct _cbdata { +#if HASHED_CBDATA + hash_link hash; +#endif int valid; int locks; int type; @@ -77,22 +84,46 @@ int line; #endif void *y; /* cookie used while debugging */ +#if !HASHED_CBDATA union { void *pointer; double double_float; int integer; } data; +#endif } cbdata; static OBJH cbdataDump; +#if HASHED_CBDATA +static MemPool *cbdata_pool = NULL; +static hash_table *cbdata_htable = NULL; +static HASHCMP cbdata_cmp; +static HASHHASH cbdata_hash; +#endif + struct { MemPool *pool; FREE *free_func; } *cbdata_index = NULL; int cbdata_types = 0; +#if HASHED_CBDATA +static int +cbdata_cmp(const void *p1, const void *p2) +{ + return (char *) p1 - (char *) p2; +} + +static unsigned int +cbdata_hash(const void *p, unsigned int mod) +{ + return ((unsigned long) p >> 8) % mod; +} + +#else #define OFFSET_OF(type, member) ((int)(char *)&((type *)0L)->member) +#endif void cbdataInitType(cbdata_type type, const char *name, int size, FREE * free_func) @@ -108,8 +139,12 @@ return; label = xmalloc(strlen(name) + 20); snprintf(label, strlen(name) + 20, "cbdata %s (%d)", name, (int) type); +#if !HASHED_CBDATA assert(OFFSET_OF(cbdata, data) == (sizeof(cbdata) - sizeof(((cbdata *) NULL)->data))); cbdata_index[type].pool = memPoolCreate(label, size + OFFSET_OF(cbdata, data)); +#else + cbdata_index[type].pool = memPoolCreate(label, size); +#endif cbdata_index[type].free_func = free_func; } @@ -150,8 +185,14 @@ CREATE_CBDATA(RemovalPolicyWalker); CREATE_CBDATA(RemovalPurgeWalker); CREATE_CBDATA(store_client); +#if HASHED_CBDATA + cbdata_pool = memPoolCreate("cbdata", sizeof(cbdata)); + cbdata_htable = hash_create(cbdata_cmp, 1 << 12, cbdata_hash); +#endif } +#define CBDATA_COOKIE(p) ((void *)((unsigned long)(p) ^ 0xDEADBEEF)) + void * #if CBDATA_DEBUG cbdataInternalAllocDbg(cbdata_type type, const char *file, int line) @@ -159,20 +200,29 @@ cbdataInternalAlloc(cbdata_type type) #endif { - cbdata *p; + cbdata *c; + void *p; assert(type > 0 && type < cbdata_types); +#if HASHED_CBDATA + c = memPoolAlloc(cbdata_pool); p = memPoolAlloc(cbdata_index[type].pool); - p->type = type; - p->valid = 1; - p->locks = 0; + c->hash.key = p; + hash_join(cbdata_htable, &c->hash); +#else + c = memPoolAlloc(cbdata_index[type].pool); + p = (void *) &c->data; +#endif + c->type = type; + c->valid = 1; + c->locks = 0; #if CBDATA_DEBUG - p->file = file; - p->line = line; + c->file = file; + c->line = line; #endif - p->y = p; + c->y = CBDATA_COOKIE(p); cbdataCount++; - return (void *) &p->data; + return p; } void * @@ -181,8 +231,12 @@ cbdata *c; FREE *free_func; debug(45, 3) ("cbdataFree: %p\n", p); +#if HASHED_CBDATA + c = (cbdata *) hash_lookup(cbdata_htable, p); +#else c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data)); - assert(c->y == c); +#endif + assert(c->y == CBDATA_COOKIE(p)); assert(c->valid); c->valid = 0; if (c->locks) { @@ -191,11 +245,18 @@ return NULL; } cbdataCount--; + c->y = NULL; debug(45, 3) ("cbdataFree: Freeing %p\n", p); free_func = cbdata_index[c->type].free_func; if (free_func) free_func((void *) p); +#if HASHED_CBDATA + hash_remove_link(cbdata_htable, &c->hash); + memPoolFree(cbdata_index[c->type].pool, p); + memPoolFree(cbdata_pool, c); +#else memPoolFree(cbdata_index[c->type].pool, c); +#endif return NULL; } @@ -204,8 +265,14 @@ { cbdata *c; assert(p); +#if HASHED_CBDATA + c = (cbdata *) hash_lookup(cbdata_htable, p); +#else c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data)); - assert(c->y == c); +#endif + assert(c->y == CBDATA_COOKIE(p)); + assert(c->locks || c->valid); + debug(45, 3) ("cbdataLocked: %p = %d\n", p, c->locks); assert(c != NULL); return c->locks; @@ -221,8 +288,13 @@ cbdata *c; if (p == NULL) return; +#if HASHED_CBDATA + c = (cbdata *) hash_lookup(cbdata_htable, p); +#else c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data)); - assert(c->y == c); +#endif + assert(c->y == CBDATA_COOKIE(p)); + assert(c->locks || c->valid); debug(45, 3) ("cbdataLock: %p\n", p); assert(c != NULL); c->locks++; @@ -243,10 +315,13 @@ FREE *free_func; if (p == NULL) return; - c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data)); - assert(c->y == c); debug(45, 3) ("cbdataUnlock: %p\n", p); - assert(c != NULL); +#if HASHED_CBDATA + c = (cbdata *) hash_lookup(cbdata_htable, p); +#else + c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data)); +#endif + assert(c->y == CBDATA_COOKIE(p)); assert(c->locks > 0); c->locks--; #if CBDATA_DEBUG @@ -260,7 +335,13 @@ free_func = cbdata_index[c->type].free_func; if (free_func) free_func((void *) p); +#if HASHED_CBDATA + hash_remove_link(cbdata_htable, &c->hash); + memPoolFree(cbdata_index[c->type].pool, (void *)p); + memPoolFree(cbdata_pool, c); +#else memPoolFree(cbdata_index[c->type].pool, c); +#endif } int @@ -270,8 +351,12 @@ if (p == NULL) return 1; /* A NULL pointer cannot become invalid */ debug(45, 3) ("cbdataValid: %p\n", p); +#if HASHED_CBDATA + c = (cbdata *) hash_lookup(cbdata_htable, p); +#else c = (cbdata *) (((char *) p) - OFFSET_OF(cbdata, data)); - assert(c->y == c); +#endif + assert(c->y == CBDATA_COOKIE(p)); assert(c->locks > 0); return c->valid; } Index: squid/src/main.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/main.c,v retrieving revision 1.42 retrieving revision 1.42.2.1 diff -u -r1.42 -r1.42.2.1 --- squid/src/main.c 28 Apr 2006 11:10:52 -0000 1.42 +++ squid/src/main.c 29 Apr 2006 00:22:20 -0000 1.42.2.1 @@ -1,6 +1,6 @@ /* - * $Id: main.c,v 1.42 2006/04/28 11:10:52 squidadm Exp $ + * $Id: main.c,v 1.42.2.1 2006/04/29 00:22:20 hno Exp $ * * DEBUG: section 1 Startup and Main Loop * AUTHOR: Harvest Derived @@ -995,7 +995,7 @@ #endif storeDirSync(); /* Flush log close */ storeFsDone(); -#if PURIFY || XMALLOC_TRACE +#if LEAK_CHECK_MODE configFreeMemory(); storeFreeMemory(); /*stmemFreeMemory(); */ Index: squid/src/mem.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/mem.c,v retrieving revision 1.22 retrieving revision 1.22.2.1 diff -u -r1.22 -r1.22.2.1 --- squid/src/mem.c 28 Apr 2006 11:10:52 -0000 1.22 +++ squid/src/mem.c 29 Apr 2006 00:22:20 -0000 1.22.2.1 @@ -1,6 +1,6 @@ /* - * $Id: mem.c,v 1.22 2006/04/28 11:10:52 squidadm Exp $ + * $Id: mem.c,v 1.22.2.1 2006/04/29 00:22:20 hno Exp $ * * DEBUG: section 13 High Level Memory Pool Management * AUTHOR: Harvest Derived @@ -101,6 +101,21 @@ memReport(sentry); memStringStats(sentry); storeBufferFlush(sentry); +#if WITH_VALGRIND + if (RUNNING_ON_VALGRIND) { + long int leaked = 0, dubious = 0, reachable = 0, suppressed = 0; + storeAppendPrintf(sentry, "Valgrind Report:\n"); + storeAppendPrintf(sentry, "Type\tAmount\n"); + debug(13, 1) ("Asking valgrind for memleaks\n"); + VALGRIND_DO_LEAK_CHECK; + debug(13, 1) ("Getting valgrind statistics\n"); + VALGRIND_COUNT_LEAKS(leaked, dubious, reachable, suppressed); + storeAppendPrintf(sentry, "Leaked\t%ld\n", leaked); + storeAppendPrintf(sentry, "Dubious\t%ld\n", dubious); + storeAppendPrintf(sentry, "Reachable\t%ld\n", reachable); + storeAppendPrintf(sentry, "Suppressed\t%ld\n", suppressed); + } +#endif } Index: squid/src/squid.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/squid.h,v retrieving revision 1.23 retrieving revision 1.23.2.1 diff -u -r1.23 -r1.23.2.1 --- squid/src/squid.h 28 Apr 2006 11:10:53 -0000 1.23 +++ squid/src/squid.h 29 Apr 2006 00:22:20 -0000 1.23.2.1 @@ -1,6 +1,6 @@ /* - * $Id: squid.h,v 1.23 2006/04/28 11:10:53 squidadm Exp $ + * $Id: squid.h,v 1.23.2.1 2006/04/29 00:22:20 hno Exp $ * * AUTHOR: Duane Wessels * @@ -94,6 +94,15 @@ #endif #if PURIFY +#define LEAK_CHECK_MODE 1 +#elif WITH_VALGRIND +#define LEAK_CHECK_MODE 1 +#elif XMALLOC_TRACE +#define LEAK_CHECK_MODE 1 +#endif + + +#if PURIFY #define assert(EX) ((void)0) #elif defined(NODEBUG) #define assert(EX) ((void)0) @@ -339,7 +348,7 @@ #define SA_RESETHAND SA_ONESHOT #endif -#if PURIFY +#if LEAK_CHECK_MODE #define LOCAL_ARRAY(type,name,size) \ static type *local_##name=NULL; \ type *name = local_##name ? local_##name : \ @@ -493,4 +502,20 @@ #error Your platform does not support large integers. Can not build with --enable-large-cache-files #endif +/* + * valgrind debug support + */ +#if WITH_VALGRIND +#include +#else +#define VALGRIND_MAKE_NOACCESS(a,b) (0) +#define VALGRIND_MAKE_WRITEABLE(a,b) (0) +#define VALGRIND_MAKE_READABLE(a,b) (0) +#define VALGRIND_CHECK_WRITEABLE(a,b) (0) +#define VALGRIND_CHECK_READABLE(a,b) (0) +#define VALGRIND_MALLOCLIKE_BLOCK(a,b,c,d) +#define VALGRIND_FREELIKE_BLOCK(a,b) +#define RUNNING_ON_VALGRIND 0 +#endif /* WITH_VALGRIND */ + #endif /* SQUID_H */ Index: squid/src/structs.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/structs.h,v retrieving revision 1.73 retrieving revision 1.73.2.1 diff -u -r1.73 -r1.73.2.1 --- squid/src/structs.h 28 Apr 2006 11:10:53 -0000 1.73 +++ squid/src/structs.h 29 Apr 2006 00:22:20 -0000 1.73.2.1 @@ -1,6 +1,6 @@ /* - * $Id: structs.h,v 1.73 2006/04/28 11:10:53 squidadm Exp $ + * $Id: structs.h,v 1.73.2.1 2006/04/29 00:22:20 hno Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -1961,6 +1961,9 @@ struct _MemPool { const char *label; size_t obj_size; +#if DEBUG_MEMPOOL + size_t real_obj_size; /* with alignment */ +#endif Stack pstack; /* stack for free pointers */ MemPoolMeter meter; };