summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2005-11-29 23:01:39 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 11:05:40 -0500
commita77658a33f84c2961fe92bec7576fb581e3c7ad6 (patch)
treed2fa73cbaba29d18694db332ce1183fd02a8d8d0
parente789a870f185227f44f950261d54b1d02e6f5a8f (diff)
downloadsamba-a77658a33f84c2961fe92bec7576fb581e3c7ad6.tar.gz
samba-a77658a33f84c2961fe92bec7576fb581e3c7ad6.tar.bz2
samba-a77658a33f84c2961fe92bec7576fb581e3c7ad6.zip
r11962: Bring talloc up to date with Samba4, re-add the
talloc_describe_all() function. Fix smbcontrol <pid> pool-usage as we desparately need it working in the field to track down memory leaks. Seriously, when new functionality like the Samba4 talloc is added, don't just disable working functionality like "pool-usage", fix the damn thing first ! Jeremy. (This used to be commit 2e262a75cca4575edd00db3d24e7e35760943120)
-rw-r--r--source3/Makefile.in2
-rw-r--r--source3/lib/talloc.c263
-rw-r--r--source3/lib/tallocmsg.c15
-rw-r--r--source3/utils/smbcontrol.c4
4 files changed, 229 insertions, 55 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in
index 26095f6d83..888a0ebe34 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -106,7 +106,7 @@ LIBSMBSHAREMODES=bin/libsmbsharemodes.a @LIBSMBSHAREMODES_SHARED@
LIBSMBSHAREMODES_MAJOR=0
LIBSMBSHAREMODES_MINOR=1
-FLAGS1 = $(CFLAGS) @FLAGS1@ -Iinclude -I$(srcdir)/include -I$(srcdir)/ubiqx -I$(srcdir)/tdb @SMBWRAP_INC@ -I. $(CPPFLAGS) -I$(srcdir)
+FLAGS1 = $(CFLAGS) @FLAGS1@ -Iinclude -I$(srcdir)/include -I$(srcdir)/ubiqx -I$(srcdir)/tdb @SMBWRAP_INC@ -I. $(CPPFLAGS) -I$(srcdir) -D_SAMBA_BUILD_
FLAGS2 =
FLAGS3 =
FLAGS4 =
diff --git a/source3/lib/talloc.c b/source3/lib/talloc.c
index 2df4588f42..b95e35152f 100644
--- a/source3/lib/talloc.c
+++ b/source3/lib/talloc.c
@@ -26,7 +26,6 @@
inspired by http://swapped.cc/halloc/
*/
-
#ifdef _SAMBA_BUILD_
#include "includes.h"
#if ((SAMBA_VERSION_MAJOR==3)&&(SAMBA_VERSION_MINOR<9))
@@ -56,8 +55,9 @@
#define MAX_TALLOC_SIZE 0x10000000
-#define TALLOC_MAGIC 0xe814ec4f
-#define TALLOC_MAGIC_FREE 0x7faebef3
+#define TALLOC_MAGIC 0xe814ec70
+#define TALLOC_FLAG_FREE 0x01
+#define TALLOC_FLAG_LOOP 0x02
#define TALLOC_MAGIC_REFERENCE ((const char *)1)
/* by default we abort when given a bad pointer (such as when talloc_free() is called
@@ -93,27 +93,27 @@ struct talloc_chunk {
struct talloc_chunk *next, *prev;
struct talloc_chunk *parent, *child;
struct talloc_reference_handle *refs;
- size_t size;
talloc_destructor_t destructor;
const char *name;
- union {
- unsigned magic;
- double align_dummy;
- } u;
+ size_t size;
+ unsigned flags;
};
+/* 16 byte alignment seems to keep everyone happy */
+#define TC_HDR_SIZE ((sizeof(struct talloc_chunk)+15)&~15)
+#define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc))
+
/* panic if we get a bad magic value */
static struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr)
{
- struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, ptr)-1;
- if (tc->u.magic != TALLOC_MAGIC) {
- if (tc->u.magic == TALLOC_MAGIC_FREE) {
- TALLOC_ABORT("Bad talloc magic value - double free");
- } else {
- TALLOC_ABORT("Bad talloc magic value - unknown value");
- }
+ const char *pp = ptr;
+ struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE);
+ if ((tc->flags & ~0xF) != TALLOC_MAGIC) {
+ TALLOC_ABORT("Bad talloc magic value - unknown value");
+ }
+ if (tc->flags & TALLOC_FLAG_FREE) {
+ TALLOC_ABORT("Bad talloc magic value - double free");
}
-
return tc;
}
@@ -158,7 +158,7 @@ static struct talloc_chunk *talloc_parent_chunk(const void *ptr)
void *talloc_parent(const void *ptr)
{
struct talloc_chunk *tc = talloc_parent_chunk(ptr);
- return tc ? (void *)(tc+1) : NULL;
+ return tc? TC_PTR_FROM_CHUNK(tc) : NULL;
}
/*
@@ -176,11 +176,11 @@ void *_talloc(const void *context, size_t size)
return NULL;
}
- tc = malloc(sizeof(*tc)+size);
+ tc = malloc(TC_HDR_SIZE+size);
if (tc == NULL) return NULL;
tc->size = size;
- tc->u.magic = TALLOC_MAGIC;
+ tc->flags = TALLOC_MAGIC;
tc->destructor = NULL;
tc->child = NULL;
tc->name = NULL;
@@ -200,7 +200,7 @@ void *_talloc(const void *context, size_t size)
tc->next = tc->prev = tc->parent = NULL;
}
- return (void *)(tc+1);
+ return TC_PTR_FROM_CHUNK(tc);
}
@@ -285,7 +285,7 @@ static int talloc_unreference(const void *context, const void *ptr)
for (h=tc->refs;h;h=h->next) {
struct talloc_chunk *p = talloc_parent_chunk(h);
- if ((p==NULL && context==NULL) || p+1 == context) break;
+ if ((p==NULL && context==NULL) || TC_PTR_FROM_CHUNK(p) == context) break;
}
if (h == NULL) {
return -1;
@@ -336,7 +336,7 @@ int talloc_unlink(const void *context, void *ptr)
new_p = talloc_parent_chunk(tc_p->refs);
if (new_p) {
- new_parent = new_p+1;
+ new_parent = TC_PTR_FROM_CHUNK(new_p);
} else {
new_parent = NULL;
}
@@ -464,6 +464,8 @@ void *talloc_init(const char *fmt, ...)
va_list ap;
void *ptr;
+ talloc_enable_null_tracking();
+
ptr = _talloc(NULL, 0);
if (ptr == NULL) return NULL;
@@ -495,16 +497,16 @@ void talloc_free_children(void *ptr)
choice is owner of any remaining reference to this
pointer, the second choice is our parent, and the
final choice is the null context. */
- void *child = tc->child+1;
+ void *child = TC_PTR_FROM_CHUNK(tc->child);
const void *new_parent = null_context;
if (tc->child->refs) {
struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs);
- if (p) new_parent = p+1;
+ if (p) new_parent = TC_PTR_FROM_CHUNK(p);
}
if (talloc_free(child) == -1) {
if (new_parent == null_context) {
struct talloc_chunk *p = talloc_parent_chunk(ptr);
- if (p) new_parent = p+1;
+ if (p) new_parent = TC_PTR_FROM_CHUNK(p);
}
talloc_steal(new_parent, child);
}
@@ -534,6 +536,11 @@ int talloc_free(void *ptr)
return -1;
}
+ if (tc->flags & TALLOC_FLAG_LOOP) {
+ /* we have a free loop - stop looping */
+ return 0;
+ }
+
if (tc->destructor) {
talloc_destructor_t d = tc->destructor;
if (d == (talloc_destructor_t)-1) {
@@ -547,6 +554,8 @@ int talloc_free(void *ptr)
tc->destructor = NULL;
}
+ tc->flags |= TALLOC_FLAG_LOOP;
+
talloc_free_children(ptr);
if (tc->parent) {
@@ -559,7 +568,7 @@ int talloc_free(void *ptr)
if (tc->next) tc->next->prev = tc->prev;
}
- tc->u.magic = TALLOC_MAGIC_FREE;
+ tc->flags |= TALLOC_FLAG_FREE;
free(tc);
return 0;
@@ -599,24 +608,24 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n
}
/* by resetting magic we catch users of the old memory */
- tc->u.magic = TALLOC_MAGIC_FREE;
+ tc->flags |= TALLOC_FLAG_FREE;
#if ALWAYS_REALLOC
- new_ptr = malloc(size + sizeof(*tc));
+ new_ptr = malloc(size + TC_HDR_SIZE);
if (new_ptr) {
- memcpy(new_ptr, tc, tc->size + sizeof(*tc));
+ memcpy(new_ptr, tc, tc->size + TC_HDR_SIZE);
free(tc);
}
#else
- new_ptr = realloc(tc, size + sizeof(*tc));
+ new_ptr = realloc(tc, size + TC_HDR_SIZE);
#endif
if (!new_ptr) {
- tc->u.magic = TALLOC_MAGIC;
+ tc->flags &= ~TALLOC_FLAG_FREE;
return NULL;
}
tc = new_ptr;
- tc->u.magic = TALLOC_MAGIC;
+ tc->flags &= ~TALLOC_FLAG_FREE;
if (tc->parent) {
tc->parent->child = new_ptr;
}
@@ -632,9 +641,9 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n
}
tc->size = size;
- talloc_set_name_const(tc+1, name);
+ talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name);
- return (void *)(tc+1);
+ return TC_PTR_FROM_CHUNK(tc);
}
/*
@@ -711,10 +720,19 @@ off_t talloc_total_size(const void *ptr)
tc = talloc_chunk_from_ptr(ptr);
+ if (tc->flags & TALLOC_FLAG_LOOP) {
+ return 0;
+ }
+
+ tc->flags |= TALLOC_FLAG_LOOP;
+
total = tc->size;
for (c=tc->child;c;c=c->next) {
- total += talloc_total_size(c+1);
+ total += talloc_total_size(TC_PTR_FROM_CHUNK(c));
}
+
+ tc->flags &= ~TALLOC_FLAG_LOOP;
+
return total;
}
@@ -726,10 +744,19 @@ off_t talloc_total_blocks(const void *ptr)
off_t total = 0;
struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
+ if (tc->flags & TALLOC_FLAG_LOOP) {
+ return 0;
+ }
+
+ tc->flags |= TALLOC_FLAG_LOOP;
+
total++;
for (c=tc->child;c;c=c->next) {
- total += talloc_total_blocks(c+1);
+ total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c));
}
+
+ tc->flags &= ~TALLOC_FLAG_LOOP;
+
return total;
}
@@ -755,23 +782,29 @@ void talloc_report_depth(const void *ptr, FILE *f, int depth)
{
struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
+ if (tc->flags & TALLOC_FLAG_LOOP) {
+ return;
+ }
+
+ tc->flags |= TALLOC_FLAG_LOOP;
+
for (c=tc->child;c;c=c->next) {
if (c->name == TALLOC_MAGIC_REFERENCE) {
- struct talloc_reference_handle *handle = (void *)(c+1);
+ struct talloc_reference_handle *handle = TC_PTR_FROM_CHUNK(c);
const char *name2 = talloc_get_name(handle->ptr);
fprintf(f, "%*sreference to: %s\n", depth*4, "", name2);
} else {
- const char *name = talloc_get_name(c+1);
+ const char *name = talloc_get_name(TC_PTR_FROM_CHUNK(c));
fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d)\n",
depth*4, "",
name,
- (unsigned long)talloc_total_size(c+1),
- (unsigned long)talloc_total_blocks(c+1),
- talloc_reference_count(c+1));
- talloc_report_depth(c+1, f, depth+1);
+ (unsigned long)talloc_total_size(TC_PTR_FROM_CHUNK(c)),
+ (unsigned long)talloc_total_blocks(TC_PTR_FROM_CHUNK(c)),
+ talloc_reference_count(TC_PTR_FROM_CHUNK(c)));
+ talloc_report_depth(TC_PTR_FROM_CHUNK(c), f, depth+1);
}
}
-
+ tc->flags &= ~TALLOC_FLAG_LOOP;
}
/*
@@ -814,9 +847,9 @@ void talloc_report(const void *ptr, FILE *f)
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));
+ talloc_get_name(TC_PTR_FROM_CHUNK(c)),
+ (unsigned long)talloc_total_size(TC_PTR_FROM_CHUNK(c)),
+ (unsigned long)talloc_total_blocks(TC_PTR_FROM_CHUNK(c)));
}
fflush(f);
}
@@ -851,6 +884,74 @@ void talloc_enable_null_tracking(void)
}
}
+#ifdef _SAMBA_BUILD_
+/* Ugly calls to Samba-specific sprintf_append... JRA. */
+
+/*
+ report on memory usage by all children of a pointer, giving a full tree view
+*/
+static void talloc_report_depth_str(const void *ptr, char **pps, ssize_t *plen, size_t *pbuflen, int depth)
+{
+ struct talloc_chunk *c, *tc = talloc_chunk_from_ptr(ptr);
+
+ if (tc->flags & TALLOC_FLAG_LOOP) {
+ return;
+ }
+
+ tc->flags |= TALLOC_FLAG_LOOP;
+
+ for (c=tc->child;c;c=c->next) {
+ if (c->name == TALLOC_MAGIC_REFERENCE) {
+ struct talloc_reference_handle *handle = TC_PTR_FROM_CHUNK(c);
+ const char *name2 = talloc_get_name(handle->ptr);
+
+ sprintf_append(NULL, pps, plen, pbuflen,
+ "%*sreference to: %s\n", depth*4, "", name2);
+
+ } else {
+ const char *name = talloc_get_name(TC_PTR_FROM_CHUNK(c));
+
+ sprintf_append(NULL, pps, plen, pbuflen,
+ "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d)\n",
+ depth*4, "",
+ name,
+ (unsigned long)talloc_total_size(TC_PTR_FROM_CHUNK(c)),
+ (unsigned long)talloc_total_blocks(TC_PTR_FROM_CHUNK(c)),
+ talloc_reference_count(TC_PTR_FROM_CHUNK(c)));
+
+ talloc_report_depth_str(TC_PTR_FROM_CHUNK(c), pps, plen, pbuflen, depth+1);
+ }
+ }
+ tc->flags &= ~TALLOC_FLAG_LOOP;
+}
+
+/*
+ report on memory usage by all children of a pointer
+*/
+char *talloc_describe_all(void)
+{
+ ssize_t len = 0;
+ size_t buflen = 512;
+ char *s = NULL;
+
+ if (null_context == NULL) {
+ return NULL;
+ }
+
+ sprintf_append(NULL, &s, &len, &buflen,
+ "full talloc report on '%s' (total %lu bytes in %lu blocks)\n",
+ talloc_get_name(null_context),
+ (unsigned long)talloc_total_size(null_context),
+ (unsigned long)talloc_total_blocks(null_context));
+
+ if (!s) {
+ return NULL;
+ }
+ talloc_report_depth_str(null_context, &s, &len, &buflen, 1);
+ return s;
+}
+#endif
+
/*
enable leak reporting on exit
*/
@@ -915,6 +1016,28 @@ char *talloc_strdup(const void *t, const char *p)
}
/*
+ append to a talloced string
+*/
+char *talloc_append_string(const void *t, char *orig, const char *append)
+{
+ char *ret;
+ size_t olen = strlen(orig);
+ size_t alenz = strlen(append) + 1;
+
+ if (!append)
+ return orig;
+
+ ret = talloc_realloc(t, orig, char, olen + alenz);
+ if (!ret)
+ return NULL;
+
+ /* append the string with the trailing \0 */
+ memcpy(&ret[olen], append, alenz);
+
+ return ret;
+}
+
+/*
strndup with a talloc
*/
char *talloc_strndup(const void *t, const char *p, size_t n)
@@ -989,6 +1112,7 @@ static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINT
static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
{
+ struct talloc_chunk *tc;
int len, s_len;
va_list ap2;
@@ -996,9 +1120,11 @@ static char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap)
return talloc_vasprintf(NULL, fmt, ap);
}
+ tc = talloc_chunk_from_ptr(s);
+
VA_COPY(ap2, ap);
- s_len = strlen(s);
+ s_len = tc->size - 1;
len = vsnprintf(NULL, 0, fmt, ap2);
s = talloc_realloc(NULL, s, char, s_len + len+1);
@@ -1102,3 +1228,46 @@ size_t talloc_get_size(const void *context)
return tc->size;
}
+
+/*
+ find a parent of this context that has the given name, if any
+*/
+void *talloc_find_parent_byname(const void *context, const char *name)
+{
+ struct talloc_chunk *tc;
+
+ if (context == NULL) {
+ return NULL;
+ }
+
+ tc = talloc_chunk_from_ptr(context);
+ while (tc) {
+ if (tc->name && strcmp(tc->name, name) == 0) {
+ return TC_PTR_FROM_CHUNK(tc);
+ }
+ while (tc && tc->prev) tc = tc->prev;
+ tc = tc->parent;
+ }
+ return NULL;
+}
+
+/*
+ show the parentage of a context
+*/
+void talloc_show_parents(const void *context, FILE *file)
+{
+ struct talloc_chunk *tc;
+
+ if (context == NULL) {
+ fprintf(file, "talloc no parents for NULL\n");
+ return;
+ }
+
+ tc = talloc_chunk_from_ptr(context);
+ fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context));
+ while (tc) {
+ fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc)));
+ while (tc && tc->prev) tc = tc->prev;
+ tc = tc->parent;
+ }
+}
diff --git a/source3/lib/tallocmsg.c b/source3/lib/tallocmsg.c
index 8f03fd66ff..b515093cd6 100644
--- a/source3/lib/tallocmsg.c
+++ b/source3/lib/tallocmsg.c
@@ -33,18 +33,23 @@
void msg_pool_usage(int msg_type, struct process_id src_pid,
void *UNUSED(buf), size_t UNUSED(len))
{
- off_t reply;
- fstring reply_str;
+ char *reply = NULL;
SMB_ASSERT(msg_type == MSG_REQ_POOL_USAGE);
DEBUG(2,("Got POOL_USAGE\n"));
- reply = talloc_total_size(NULL);
- fstr_sprintf(reply_str, "%ld", (long)reply);
+ reply = talloc_describe_all();
+ if (!reply) {
+ return;
+ }
+ become_root();
message_send_pid(src_pid, MSG_POOL_USAGE,
- reply_str, strlen(reply_str)+1, True);
+ reply, strlen(reply)+1, True);
+ unbecome_root();
+
+ SAFE_FREE(reply);
}
/**
diff --git a/source3/utils/smbcontrol.c b/source3/utils/smbcontrol.c
index a0304eb89a..25b42a58c1 100644
--- a/source3/utils/smbcontrol.c
+++ b/source3/utils/smbcontrol.c
@@ -508,13 +508,13 @@ static BOOL do_poolusage(const struct process_id pid,
return False;
}
+ message_register(MSG_POOL_USAGE, print_string_cb);
+
/* Send a message and register our interest in a reply */
if (!send_message(pid, MSG_REQ_POOL_USAGE, NULL, 0, False))
return False;
- message_register(MSG_POOL_USAGE, print_string_cb);
-
wait_replies(procid_to_pid(&pid) == 0);
/* No replies were received within the timeout period */