diff --git a/CHANGES b/CHANGES index 78573336f7..7ea44525f7 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,5 @@ +1949. [func] Addition memory leakage checks. [RT #15544] + 1948. [bug] If was possible to trigger a REQUIRE failure in xfrin.c:maybe_free() if named ran out of memory. [RT #15568] diff --git a/bin/named/main.c b/bin/named/main.c index c80798d5c3..a6fc8fadaa 100644 --- a/bin/named/main.c +++ b/bin/named/main.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: main.c,v 1.149 2005/09/18 07:16:19 marka Exp $ */ +/* $Id: main.c,v 1.150 2006/01/04 03:16:47 marka Exp $ */ /*! \file */ @@ -912,6 +912,7 @@ main(int argc, char *argv[]) { } } isc_mem_destroy(&ns_g_mctx); + isc_mem_checkdestroyed(stderr); ns_main_setmemstats(NULL); diff --git a/lib/isc/include/isc/mem.h b/lib/isc/include/isc/mem.h index 7b5f8e6f22..2c9f1ab688 100644 --- a/lib/isc/include/isc/mem.h +++ b/lib/isc/include/isc/mem.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: mem.h,v 1.66 2005/10/26 04:35:55 marka Exp $ */ +/* $Id: mem.h,v 1.67 2006/01/04 03:16:47 marka Exp $ */ #ifndef ISC_MEM_H #define ISC_MEM_H 1 @@ -352,6 +352,30 @@ isc_mem_setwater(isc_mem_t *mctx, isc_mem_water_t water, void *water_arg, * hi_water >= lo_water */ +void +isc_mem_printactive(isc_mem_t *mctx, FILE *file); +/*%< + * Print to 'file' all active memory in 'mctx'. + * + * Requires ISC_MEM_DEBUGRECORD to have been set. + */ + +void +isc_mem_printallactive(FILE *file); +/*%< + * Print to 'file' all active memory in all contexts. + * + * Requires ISC_MEM_DEBUGRECORD to have been set. + */ + +void +isc_mem_checkdestroyed(FILE *file); +/*%< + * Check that all memory contexts have been destroyed. + * Prints out those that have not been. + * Fatally fails if there are still active contexts. + */ + /* * Memory pools */ diff --git a/lib/isc/mem.c b/lib/isc/mem.c index 529a77d659..be601753bd 100644 --- a/lib/isc/mem.c +++ b/lib/isc/mem.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: mem.c,v 1.124 2005/08/23 04:05:50 marka Exp $ */ +/* $Id: mem.c,v 1.125 2006/01/04 03:16:47 marka Exp $ */ /*! \file */ @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -106,6 +107,12 @@ struct stats { typedef ISC_LIST(debuglink_t) debuglist_t; #endif +/* List of all active memory contexts. */ + +static ISC_LIST(isc_mem_t) contexts; +static isc_once_t once = ISC_ONCE_INIT; +static isc_mutex_t lock; + struct isc_mem { unsigned int magic; isc_ondestroy_t ondestroy; @@ -144,6 +151,7 @@ struct isc_mem { #endif unsigned int memalloc_failures; + ISC_LINK(isc_mem_t) link; }; #define MEMPOOL_MAGIC ISC_MAGIC('M', 'E', 'M', 'p') @@ -680,6 +688,11 @@ default_memfree(void *arg, void *ptr) { free(ptr); } +static void +initialize_action(void) { + RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS); +} + /* * Public. */ @@ -708,6 +721,8 @@ isc_mem_createx2(size_t init_max_size, size_t target_size, INSIST((ALIGNMENT_SIZE & (ALIGNMENT_SIZE - 1)) == 0); + RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); + ctx = (memalloc)(arg, sizeof(*ctx)); if (ctx == NULL) return (ISC_R_NOMEMORY); @@ -794,6 +809,10 @@ isc_mem_createx2(size_t init_max_size, size_t target_size, ctx->memalloc_failures = 0; + LOCK(&lock); + ISC_LIST_INITANDAPPEND(contexts, ctx, link); + UNLOCK(&lock); + *ctxp = ctx; return (ISC_R_SUCCESS); @@ -840,6 +859,10 @@ destroy(isc_mem_t *ctx) { ctx->magic = 0; + LOCK(&lock); + ISC_LIST_UNLINK(contexts, ctx, link); + UNLOCK(&lock); + INSIST(ISC_LIST_EMPTY(ctx->pools)); #if ISC_MEM_TRACKLINES @@ -1858,3 +1881,60 @@ isc_mempool_getfillcount(isc_mempool_t *mpctx) { return (fillcount); } + +void +isc_mem_printactive(isc_mem_t *ctx, FILE *file) { + + REQUIRE(VALID_CONTEXT(ctx)); + REQUIRE(file != NULL); + +#if !ISC_MEM_TRACKLINES + UNUSED(ctx); + UNUSED(file); +#else + print_active(ctx, file); +#endif +} + +void +isc_mem_printallactive(FILE *file) { +#if !ISC_MEM_TRACKLINES + UNUSED(file); +#else + isc_mem_t *ctx; + + RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); + + LOCK(&lock); + for (ctx = ISC_LIST_HEAD(contexts); + ctx != NULL; + ctx = ISC_LIST_NEXT(ctx, link)) { + fprintf(file, "context: %p\n", ctx); + print_active(ctx, file); + } + UNLOCK(&lock); +#endif +} + +void +isc_mem_checkdestroyed(FILE *file) { + + RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS); + + LOCK(&lock); + if (!ISC_LIST_EMPTY(contexts)) { +#if ISC_MEM_TRACKLINES + isc_mem_t *ctx; + + for (ctx = ISC_LIST_HEAD(contexts); + ctx != NULL; + ctx = ISC_LIST_NEXT(ctx, link)) { + fprintf(file, "context: %p\n", ctx); + print_active(ctx, file); + } + fflush(file); +#endif + INSIST(1); + } + UNLOCK(&lock); +} diff --git a/lib/isc/task.c b/lib/isc/task.c index 2d11967e97..b54f4aee58 100644 --- a/lib/isc/task.c +++ b/lib/isc/task.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: task.c,v 1.95 2005/07/12 01:00:18 marka Exp $ */ +/* $Id: task.c,v 1.96 2006/01/04 03:16:47 marka Exp $ */ /*! \file * \author Principal Author: Bob Halley @@ -1229,6 +1229,8 @@ isc_taskmgr_destroy(isc_taskmgr_t **managerp) { UNLOCK(&manager->lock); while (isc__taskmgr_ready()) (void)isc__taskmgr_dispatch(); + if (!ISC_LIST_EMPTY(manager->tasks)) + isc_mem_printallactive(stderr); INSIST(ISC_LIST_EMPTY(manager->tasks)); #endif /* ISC_PLATFORM_USETHREADS */