From 351ca44e8b3ea8336abba8215dfc1ccb42458384 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 27 Sep 2004 04:20:18 +0000 Subject: r2674: I have realised that talloc() should have its context marked const, as a const pointer really means that "the data pointed to by this pointer won't change", and that is certainly true of talloc(). The fact that some behind-the-scenes meta-data can change doesn't matter from the point of view of const. this fixes a number of const warnings caused by const data structures being passed as talloc contexts. That will no longer generate a warning. also changed the talloc leak reporting option from --leak-check to --leak-report, as all it does is generate a report on exit. A new --leak-report-full option has been added that shows the complete tree of memory allocations, which is is quite useful in tracking things down. NOTE: I find it quite useful to insert talloc_report_full(ptr, stderr) calls at strategic points in the code while debugging memory allocation problems, particularly before freeing a major context (such as the connection context). This allows you to see if that context has been accumulating too much data, such as per-request data, which should have been freed when the request finished. (This used to be commit c60ff99c3129c26a9204bac1c6e5fb386114a923) --- source4/lib/cmdline/popt_common.c | 13 +++-- source4/lib/data_blob.c | 11 +--- source4/lib/talloc.c | 118 +++++++++++++++++++++++++++----------- 3 files changed, 96 insertions(+), 46 deletions(-) (limited to 'source4/lib') diff --git a/source4/lib/cmdline/popt_common.c b/source4/lib/cmdline/popt_common.c index f98c460642..725a5060c0 100644 --- a/source4/lib/cmdline/popt_common.c +++ b/source4/lib/cmdline/popt_common.c @@ -34,7 +34,7 @@ */ -enum {OPT_OPTION=1,OPT_LEAK_CHECK=2}; +enum {OPT_OPTION=1,OPT_LEAK_REPORT,OPT_LEAK_REPORT_FULL}; static struct cmdline_auth_info cmdline_auth_info; @@ -117,8 +117,12 @@ static void popt_common_callback(poptContext con, } break; - case OPT_LEAK_CHECK: - talloc_enable_leak_check(); + case OPT_LEAK_REPORT: + talloc_enable_leak_report(); + break; + + case OPT_LEAK_REPORT_FULL: + talloc_enable_leak_report_full(); break; } } @@ -140,7 +144,8 @@ struct poptOption popt_common_samba[] = { { "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 }, + { "leak-report", 0, POPT_ARG_NONE, NULL, OPT_LEAK_REPORT, "enable talloc leak reporting on exit", NULL }, + { "leak-report-full",0, POPT_ARG_NONE, NULL, OPT_LEAK_REPORT_FULL, "enable full talloc leak reporting on exit", NULL }, POPT_TABLEEND }; diff --git a/source4/lib/data_blob.c b/source4/lib/data_blob.c index b09148b63e..7803179d39 100644 --- a/source4/lib/data_blob.c +++ b/source4/lib/data_blob.c @@ -51,17 +51,12 @@ DATA_BLOB data_blob_named(const void *p, size_t length, const char *name) /******************************************************************* construct a data blob, using supplied TALLOC_CTX *******************************************************************/ -DATA_BLOB data_blob_talloc(TALLOC_CTX *mem_ctx, const void *p, size_t length) +DATA_BLOB data_blob_talloc_named(TALLOC_CTX *mem_ctx, const void *p, size_t length, const char *name) { - DATA_BLOB ret = data_blob(p, length); + DATA_BLOB ret = data_blob_named(p, length, name); if (ret.data) { - ret.data = talloc_steal(mem_ctx, ret.data); - } else { - /* this ensures the blob has the context attached, so a zero length call - to data_blob_talloc followed by a realloc doesn't cause the memory to come - from the NULL context */ - ret.data = talloc(mem_ctx, 0); + talloc_steal(mem_ctx, ret.data); } return ret; } diff --git a/source4/lib/talloc.c b/source4/lib/talloc.c index 7266ff8a45..ce8f1c5272 100644 --- a/source4/lib/talloc.c +++ b/source4/lib/talloc.c @@ -30,7 +30,7 @@ #define TALLOC_MAGIC 0xe814ec4f #define TALLOC_MAGIC_FREE 0x7faebef3 -static void *null_context; +static const void *null_context; struct talloc_chunk { struct talloc_chunk *next, *prev; @@ -43,9 +43,9 @@ struct talloc_chunk { }; /* panic if we get a bad magic value */ -static struct talloc_chunk *talloc_chunk_from_ptr(void *ptr) +static struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr) { - struct talloc_chunk *tc = ((struct talloc_chunk *)ptr)-1; + struct talloc_chunk *tc = ((struct talloc_chunk *)discard_const(ptr))-1; if (tc->magic != TALLOC_MAGIC) { if (tc->magic == TALLOC_MAGIC_FREE) { smb_panic("Bad talloc magic value - double free\n"); @@ -59,7 +59,7 @@ static struct talloc_chunk *talloc_chunk_from_ptr(void *ptr) /* Allocate a bit of memory as a child of an existing pointer */ -void *_talloc(void *context, size_t size) +void *_talloc(const void *context, size_t size) { struct talloc_chunk *tc; @@ -107,7 +107,7 @@ void *_talloc(void *context, size_t size) if the destructor fails then the free is failed, and the memory can be continued to be used */ -void talloc_set_destructor(void *ptr, int (*destructor)(void *)) +void talloc_set_destructor(const void *ptr, int (*destructor)(void *)) { struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); tc->destructor = destructor; @@ -118,7 +118,7 @@ void talloc_set_destructor(void *ptr, int (*destructor)(void *)) reference count call talloc_free(), which will free the memory if the reference count reaches zero */ -void talloc_increase_ref_count(void *ptr) +void talloc_increase_ref_count(const void *ptr) { struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); tc->ref_count++; @@ -128,9 +128,9 @@ void talloc_increase_ref_count(void *ptr) /* add a name to an existing pointer - va_list version */ -static void talloc_set_name_v(void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); +static void talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); -static void talloc_set_name_v(void *ptr, const char *fmt, va_list ap) +static void talloc_set_name_v(const void *ptr, const char *fmt, va_list ap) { struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); tc->name = talloc_vasprintf(ptr, fmt, ap); @@ -139,7 +139,7 @@ static void talloc_set_name_v(void *ptr, const char *fmt, va_list ap) /* add a name to an existing pointer */ -void talloc_set_name(void *ptr, const char *fmt, ...) _PRINTF_ATTRIBUTE(2,3) +void talloc_set_name(const void *ptr, const char *fmt, ...) _PRINTF_ATTRIBUTE(2,3) { va_list ap; va_start(ap, fmt); @@ -151,7 +151,7 @@ void talloc_set_name(void *ptr, const char *fmt, ...) _PRINTF_ATTRIBUTE(2,3) more efficient way to add a name to a pointer - the name must point to a true string constant */ -void talloc_set_name_const(void *ptr, const char *name) +void talloc_set_name_const(const void *ptr, const char *name) { struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); tc->name = name; @@ -162,7 +162,7 @@ void talloc_set_name_const(void *ptr, const char *name) talloc_named() operates just like talloc() except that it allows you to name the pointer. */ -void *talloc_named(void *context, size_t size, +void *talloc_named(const void *context, size_t size, const char *fmt, ...) _PRINTF_ATTRIBUTE(3,4) { va_list ap; @@ -185,7 +185,7 @@ void *talloc_named(void *context, size_t size, talloc_named() operates just like talloc() except that it allows you to name the pointer. */ -void *talloc_named_const(void *context, size_t size, const char *name) +void *talloc_named_const(const void *context, size_t size, const char *name) { void *ptr; @@ -202,7 +202,7 @@ void *talloc_named_const(void *context, size_t size, const char *name) /* return the name of a talloc ptr, or "UNNAMED" */ -const char *talloc_get_name(void *ptr) +const char *talloc_get_name(const void *ptr) { struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); if (tc->name) { @@ -290,7 +290,7 @@ int talloc_free(void *ptr) A talloc version of realloc. The context argument is only used if ptr is NULL */ -void *_talloc_realloc(void *context, void *ptr, size_t size, const char *name) +void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name) { struct talloc_chunk *tc; void *new_ptr; @@ -340,7 +340,7 @@ void *_talloc_realloc(void *context, void *ptr, size_t size, const char *name) move a lump of memory from one talloc context to another return the ptr on success, or NUL if it could not be transferred */ -void *talloc_steal(void *new_ctx, void *ptr) +void *talloc_steal(const void *new_ctx, const void *ptr) { struct talloc_chunk *tc, *new_tc; @@ -352,7 +352,7 @@ void *talloc_steal(void *new_ctx, void *ptr) new_tc = talloc_chunk_from_ptr(new_ctx); if (tc == new_tc) { - return ptr; + discard_const(ptr); } if (tc->parent) { @@ -369,13 +369,13 @@ void *talloc_steal(void *new_ctx, void *ptr) if (new_tc->child) new_tc->child->parent = NULL; DLIST_ADD(new_tc->child, tc); - return ptr; + return discard_const(ptr); } /* return the total size of a talloc pool (subtree) */ -static off_t talloc_total_size(void *ptr) +static off_t talloc_total_size(const void *ptr) { off_t total = 0; struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr); @@ -390,7 +390,7 @@ static off_t talloc_total_size(void *ptr) /* return the total number of blocks in a talloc pool (subtree) */ -static off_t talloc_total_blocks(void *ptr) +static off_t talloc_total_blocks(const void *ptr) { off_t total = 0; struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr); @@ -402,10 +402,41 @@ static off_t talloc_total_blocks(void *ptr) return total; } +/* + report on memory usage by all children of a pointer, giving a full tree view +*/ +static void talloc_report_depth(const void *ptr, FILE *f, int depth) +{ + struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr); + + for (c=tc->child;c;c=c->next) { + fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks\n", + depth*2, "", + talloc_get_name(c+1), + (unsigned long)talloc_total_size(c+1), + (unsigned long)talloc_total_blocks(c+1)); + talloc_report_depth(c+1, f, depth+1); + } + +} + +/* + report on memory usage by all children of a pointer, giving a full tree view +*/ +void talloc_report_full(const void *ptr, FILE *f) +{ + fprintf(f,"full 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)); + + talloc_report_depth(ptr, f, 1); +} + /* report on memory usage by all children of a pointer */ -void talloc_report(void *ptr, FILE *f) +void talloc_report(const void *ptr, FILE *f) { struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr); @@ -426,7 +457,7 @@ void talloc_report(void *ptr, FILE *f) /* report on any memory hanging off the null context */ -static void talloc_report_all(void) +static void talloc_report_null(void) { if (talloc_total_size(null_context) == 0) { return; @@ -434,21 +465,41 @@ static void talloc_report_all(void) talloc_report(null_context, stderr); } +/* + report on any memory hanging off the null context +*/ +static void talloc_report_null_full(void) +{ + if (talloc_total_size(null_context) == 0) { + return; + } + talloc_report_full(null_context, stderr); +} + /* enable leak reporting on exit */ -void talloc_enable_leak_check(void) +void talloc_enable_leak_report(void) +{ + null_context = talloc_named_const(NULL, 0, "null_context"); + atexit(talloc_report_null); +} + +/* + enable full leak reporting on exit +*/ +void talloc_enable_leak_report_full(void) { null_context = talloc_named_const(NULL, 0, "null_context"); - atexit(talloc_report_all); + atexit(talloc_report_null_full); } /* talloc and zero memory. */ -void *talloc_zero(void *t, size_t size) +void *talloc_zero(const void *ctx, size_t size) { - void *p = talloc(t, size); + void *p = talloc(ctx, size); if (p) { memset(p, '\0', size); @@ -461,13 +512,12 @@ void *talloc_zero(void *t, size_t size) /* memdup with a talloc. */ -void *_talloc_memdup(void *t, const void *p, size_t size, const char *name) +void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name) { - void *newp = _talloc(t,size); + void *newp = talloc_named_const(t, size, name); if (newp) { memcpy(newp, p, size); - talloc_set_name_const(newp, name); } return newp; @@ -476,7 +526,7 @@ void *_talloc_memdup(void *t, const void *p, size_t size, const char *name) /* strdup with a talloc */ -char *talloc_strdup(void *t, const char *p) +char *talloc_strdup(const void *t, const char *p) { char *ret; if (!p) { @@ -492,7 +542,7 @@ char *talloc_strdup(void *t, const char *p) /* strndup with a talloc */ -char *talloc_strndup(void *t, const char *p, size_t n) +char *talloc_strndup(const void *t, const char *p, size_t n) { size_t len = strnlen(p, n); char *ret; @@ -504,7 +554,7 @@ char *talloc_strndup(void *t, const char *p, size_t n) return ret; } -char *talloc_vasprintf(void *t, const char *fmt, va_list ap) _PRINTF_ATTRIBUTE(2,0) +char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) _PRINTF_ATTRIBUTE(2,0) { int len; char *ret; @@ -529,7 +579,7 @@ char *talloc_vasprintf(void *t, const char *fmt, va_list ap) _PRINTF_ATTRIBUTE(2 Perform string formatting, and return a pointer to newly allocated memory holding the result, inside a memory pool. */ -char *talloc_asprintf(void *t, const char *fmt, ...) _PRINTF_ATTRIBUTE(2,3) +char *talloc_asprintf(const void *t, const char *fmt, ...) _PRINTF_ATTRIBUTE(2,3) { va_list ap; char *ret; @@ -595,7 +645,7 @@ char *talloc_asprintf_append(char *s, /* alloc an array, checking for integer overflow in the array size */ -void *talloc_array(void *ctx, size_t el_size, uint_t count, const char *name) +void *talloc_array(const void *ctx, size_t el_size, uint_t count, const char *name) { if (count == 0 || count >= MAX_TALLOC_SIZE/el_size) { @@ -608,7 +658,7 @@ void *talloc_array(void *ctx, size_t el_size, uint_t count, const char *name) /* realloc an array, checking for integer overflow in the array size */ -void *talloc_realloc_array(void *ctx, void *ptr, size_t el_size, uint_t count, const char *name) +void *talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, uint_t count, const char *name) { if (count == 0 || count >= MAX_TALLOC_SIZE/el_size) { -- cgit