diff options
-rw-r--r-- | source4/lib/cmdline/popt_common.c | 13 | ||||
-rw-r--r-- | source4/lib/talloc.c | 72 |
2 files changed, 80 insertions, 5 deletions
diff --git a/source4/lib/cmdline/popt_common.c b/source4/lib/cmdline/popt_common.c index e2deb5db96..f98c460642 100644 --- a/source4/lib/cmdline/popt_common.c +++ b/source4/lib/cmdline/popt_common.c @@ -34,7 +34,7 @@ */ -enum {OPT_OPTION=1}; +enum {OPT_OPTION=1,OPT_LEAK_CHECK=2}; static struct cmdline_auth_info cmdline_auth_info; @@ -116,6 +116,10 @@ static void popt_common_callback(poptContext con, exit(1); } break; + + case OPT_LEAK_CHECK: + talloc_enable_leak_check(); + break; } } @@ -132,10 +136,11 @@ struct poptOption popt_common_connection[] = { struct poptOption popt_common_samba[] = { { NULL, 0, POPT_ARG_CALLBACK|POPT_CBFLAG_PRE, popt_common_callback }, - { "debuglevel", 'd', POPT_ARG_STRING, NULL, 'd', "Set debug level", "DEBUGLEVEL" }, - { "configfile", 's', POPT_ARG_STRING, NULL, 's', "Use alternative configuration file", "CONFIGFILE" }, - { "option", 0, POPT_ARG_STRING, NULL, OPT_OPTION, "Set smb.conf option from command line", "name=value" }, + { "debuglevel", 'd', POPT_ARG_STRING, NULL, 'd', "Set debug level", "DEBUGLEVEL" }, + { "configfile", 's', POPT_ARG_STRING, NULL, 's', "Use alternative configuration file", "CONFIGFILE" }, + { "option", 0, POPT_ARG_STRING, NULL, OPT_OPTION, "Set smb.conf option from command line", "name=value" }, { "log-basename", 'l', POPT_ARG_STRING, NULL, 'l', "Basename for log/debug files", "LOGFILEBASE" }, + { "leak-check", 0, POPT_ARG_NONE, NULL, OPT_LEAK_CHECK, "enable talloc leak checking", NULL }, POPT_TABLEEND }; diff --git a/source4/lib/talloc.c b/source4/lib/talloc.c index c236834d91..114d0de43b 100644 --- a/source4/lib/talloc.c +++ b/source4/lib/talloc.c @@ -30,6 +30,8 @@ #define TALLOC_MAGIC 0xe814ec4f #define TALLOC_MAGIC_FREE 0x7faebef3 +static void *null_context; + struct talloc_chunk { struct talloc_chunk *next, *prev; struct talloc_chunk *parent, *child; @@ -61,6 +63,10 @@ void *talloc(void *context, size_t size) { struct talloc_chunk *tc; + if (context == NULL) { + context = null_context; + } + if (size >= MAX_TALLOC_SIZE) { return NULL; } @@ -165,6 +171,18 @@ void *talloc_named(void *context, size_t size, } /* + return the name of a talloc ptr, or "UNNAMED" +*/ +const char *talloc_get_name(void *ptr) +{ + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); + if (tc->name) { + return tc->name; + } + return "UNNAMED"; +} + +/* this is for compatibility with older versions of talloc */ void *talloc_init(const char *fmt, ...) _PRINTF_ATTRIBUTE(1,2) @@ -327,7 +345,7 @@ void *talloc_steal(void *new_ctx, void *ptr) /* return the total size of a talloc pool (subtree) */ -off_t talloc_total_size(void *ptr) +static off_t talloc_total_size(void *ptr) { off_t total = 0; struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr); @@ -339,6 +357,58 @@ off_t talloc_total_size(void *ptr) return total; } +/* + return the total number of blocks in a talloc pool (subtree) +*/ +static off_t talloc_total_blocks(void *ptr) +{ + off_t total = 0; + struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr); + + total++; + for (c=tc->child;c;c=c->next) { + total += talloc_total_blocks(c+1); + } + return total; +} + +/* + report on memory usage by all children of a pointer +*/ +void talloc_report(void *ptr, FILE *f) +{ + struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr); + + fprintf(f,"talloc report on '%s' (total %lu bytes in %lu blocks)\n", + talloc_get_name(ptr), + (unsigned long)talloc_total_size(ptr), + (unsigned long)talloc_total_blocks(ptr)); + + for (c=tc->child;c;c=c->next) { + fprintf(f, "\t%-30s contains %6lu bytes in %3lu blocks\n", + talloc_get_name(c+1), + (unsigned long)talloc_total_size(c+1), + (unsigned long)talloc_total_blocks(c+1)); + } + +} + +/* + report on any memory hanging off the null context +*/ +static void talloc_report_all(void) +{ + talloc_report(null_context, stderr); +} + +/* + enable leak reporting on exit +*/ +void talloc_enable_leak_check(void) +{ + null_context = talloc_named(NULL, 0, "null_context"); + atexit(talloc_report_all); +} /* talloc and zero memory. |